ARM: entry: data abort: always use r6 for offset
[sfrench/cifs-2.6.git] / arch / arm / mm / abort-lv4t.S
1 #include <linux/linkage.h>
2 #include <asm/assembler.h>
3 /*
4  * Function: v4t_late_abort
5  *
6  * Params  : r2 = pt_regs
7  *         : r4 = aborted context pc
8  *         : r5 = aborted context psr
9  *
10  * Returns : r0 = address of abort
11  *         : r1 = FSR, bit 11 = write
12  *         : r2-r8 = corrupted
13  *         : r9 = preserved
14  *         : sp = pointer to registers
15  *
16  * Purpose : obtain information about current aborted instruction.
17  * Note: we read user space.  This means we might cause a data
18  * abort here if the I-TLB and D-TLB aren't seeing the same
19  * picture.  Unfortunately, this does happen.  We live with it.
20  */
21 ENTRY(v4t_late_abort)
22         tst     r5, #PSR_T_BIT                  @ check for thumb mode
23 #ifdef CONFIG_CPU_CP15_MMU
24         mrc     p15, 0, r1, c5, c0, 0           @ get FSR
25         mrc     p15, 0, r0, c6, c0, 0           @ get FAR
26         bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
27 #else
28         mov     r0, #0                          @ clear r0, r1 (no FSR/FAR)
29         mov     r1, #0
30 #endif
31         bne     .data_thumb_abort
32         ldr     r8, [r4]                        @ read arm instruction
33         tst     r8, #1 << 20                    @ L = 1 -> write?
34         orreq   r1, r1, #1 << 11                @ yes.
35         and     r7, r8, #15 << 24
36         add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
37         nop
38
39 /* 0 */ b       .data_arm_lateldrhpost          @ ldrh  rd, [rn], #m/rm
40 /* 1 */ b       .data_arm_lateldrhpre           @ ldrh  rd, [rn, #m/rm]
41 /* 2 */ b       .data_unknown
42 /* 3 */ b       .data_unknown
43 /* 4 */ b       .data_arm_lateldrpostconst      @ ldr   rd, [rn], #m
44 /* 5 */ b       .data_arm_lateldrpreconst       @ ldr   rd, [rn, #m] 
45 /* 6 */ b       .data_arm_lateldrpostreg        @ ldr   rd, [rn], rm
46 /* 7 */ b       .data_arm_lateldrprereg         @ ldr   rd, [rn, rm]
47 /* 8 */ b       .data_arm_ldmstm                @ ldm*a rn, <rlist>
48 /* 9 */ b       .data_arm_ldmstm                @ ldm*b rn, <rlist>
49 /* a */ b       .data_unknown
50 /* b */ b       .data_unknown
51 /* c */ b       do_DataAbort                    @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
52 /* d */ b       do_DataAbort                    @ ldc   rd, [rn, #m]
53 /* e */ b       .data_unknown
54 /* f */
55 .data_unknown:  @ Part of jumptable
56         mov     r0, r4
57         mov     r1, r8
58         b       baddataabort
59
60 .data_arm_ldmstm:
61         tst     r8, #1 << 21                    @ check writeback bit
62         beq     do_DataAbort                    @ no writeback -> no fixup
63         mov     r7, #0x11
64         orr     r7, r7, #0x1100
65         and     r6, r8, r7
66         and     r9, r8, r7, lsl #1
67         add     r6, r6, r9, lsr #1
68         and     r9, r8, r7, lsl #2
69         add     r6, r6, r9, lsr #2
70         and     r9, r8, r7, lsl #3
71         add     r6, r6, r9, lsr #3
72         add     r6, r6, r6, lsr #8
73         add     r6, r6, r6, lsr #4
74         and     r6, r6, #15                     @ r6 = no. of registers to transfer.
75         and     r5, r8, #15 << 16               @ Extract 'n' from instruction
76         ldr     r7, [r2, r5, lsr #14]           @ Get register 'Rn'
77         tst     r8, #1 << 23                    @ Check U bit
78         subne   r7, r7, r6, lsl #2              @ Undo increment
79         addeq   r7, r7, r6, lsl #2              @ Undo decrement
80         str     r7, [r2, r5, lsr #14]           @ Put register 'Rn'
81         b       do_DataAbort
82
83 .data_arm_lateldrhpre:
84         tst     r8, #1 << 21                    @ Check writeback bit
85         beq     do_DataAbort                    @ No writeback -> no fixup
86 .data_arm_lateldrhpost:
87         and     r5, r8, #0x00f                  @ get Rm / low nibble of immediate value
88         tst     r8, #1 << 22                    @ if (immediate offset)
89         andne   r6, r8, #0xf00                  @ { immediate high nibble
90         orrne   r6, r5, r6, lsr #4              @   combine nibbles } else
91         ldreq   r6, [r2, r5, lsl #2]            @ { load Rm value }
92 .data_arm_apply_r6_and_rn:
93         and     r5, r8, #15 << 16               @ Extract 'n' from instruction
94         ldr     r7, [r2, r5, lsr #14]           @ Get register 'Rn'
95         tst     r8, #1 << 23                    @ Check U bit
96         subne   r7, r7, r6                      @ Undo incrmenet
97         addeq   r7, r7, r6                      @ Undo decrement
98         str     r7, [r2, r5, lsr #14]           @ Put register 'Rn'
99         b       do_DataAbort
100
101 .data_arm_lateldrpreconst:
102         tst     r8, #1 << 21                    @ check writeback bit
103         beq     do_DataAbort                    @ no writeback -> no fixup
104 .data_arm_lateldrpostconst:
105         movs    r6, r8, lsl #20                 @ Get offset
106         beq     do_DataAbort                    @ zero -> no fixup
107         and     r5, r8, #15 << 16               @ Extract 'n' from instruction
108         ldr     r7, [r2, r5, lsr #14]           @ Get register 'Rn'
109         tst     r8, #1 << 23                    @ Check U bit
110         subne   r7, r7, r6, lsr #20             @ Undo increment
111         addeq   r7, r7, r6, lsr #20             @ Undo decrement
112         str     r7, [r2, r5, lsr #14]           @ Put register 'Rn'
113         b       do_DataAbort
114
115 .data_arm_lateldrprereg:
116         tst     r8, #1 << 21                    @ check writeback bit
117         beq     do_DataAbort                    @ no writeback -> no fixup
118 .data_arm_lateldrpostreg:
119         and     r7, r8, #15                     @ Extract 'm' from instruction
120         ldr     r6, [r2, r7, lsl #2]            @ Get register 'Rm'
121         mov     r5, r8, lsr #7                  @ get shift count
122         ands    r5, r5, #31
123         and     r7, r8, #0x70                   @ get shift type
124         orreq   r7, r7, #8                      @ shift count = 0
125         add     pc, pc, r7
126         nop
127
128         mov     r6, r6, lsl r5                  @ 0: LSL #!0
129         b       .data_arm_apply_r6_and_rn
130         b       .data_arm_apply_r6_and_rn       @ 1: LSL #0
131         nop
132         b       .data_unknown                   @ 2: MUL?
133         nop
134         b       .data_unknown                   @ 3: MUL?
135         nop
136         mov     r6, r6, lsr r5                  @ 4: LSR #!0
137         b       .data_arm_apply_r6_and_rn
138         mov     r6, r6, lsr #32                 @ 5: LSR #32
139         b       .data_arm_apply_r6_and_rn
140         b       .data_unknown                   @ 6: MUL?
141         nop
142         b       .data_unknown                   @ 7: MUL?
143         nop
144         mov     r6, r6, asr r5                  @ 8: ASR #!0
145         b       .data_arm_apply_r6_and_rn
146         mov     r6, r6, asr #32                 @ 9: ASR #32
147         b       .data_arm_apply_r6_and_rn
148         b       .data_unknown                   @ A: MUL?
149         nop
150         b       .data_unknown                   @ B: MUL?
151         nop
152         mov     r6, r6, ror r5                  @ C: ROR #!0
153         b       .data_arm_apply_r6_and_rn
154         mov     r6, r6, rrx                     @ D: RRX
155         b       .data_arm_apply_r6_and_rn
156         b       .data_unknown                   @ E: MUL?
157         nop
158         b       .data_unknown                   @ F: MUL?
159
160 .data_thumb_abort:
161         ldrh    r8, [r4]                        @ read instruction
162         tst     r8, #1 << 11                    @ L = 1 -> write?
163         orreq   r1, r1, #1 << 8                 @ yes
164         and     r7, r8, #15 << 12
165         add     pc, pc, r7, lsr #10             @ lookup in table
166         nop
167
168 /* 0 */ b       .data_unknown
169 /* 1 */ b       .data_unknown
170 /* 2 */ b       .data_unknown
171 /* 3 */ b       .data_unknown
172 /* 4 */ b       .data_unknown
173 /* 5 */ b       .data_thumb_reg
174 /* 6 */ b       do_DataAbort
175 /* 7 */ b       do_DataAbort
176 /* 8 */ b       do_DataAbort
177 /* 9 */ b       do_DataAbort
178 /* A */ b       .data_unknown
179 /* B */ b       .data_thumb_pushpop
180 /* C */ b       .data_thumb_ldmstm
181 /* D */ b       .data_unknown
182 /* E */ b       .data_unknown
183 /* F */ b       .data_unknown
184
185 .data_thumb_reg:
186         tst     r8, #1 << 9
187         beq     do_DataAbort
188         tst     r8, #1 << 10                    @ If 'S' (signed) bit is set
189         movne   r1, #0                          @ it must be a load instr
190         b       do_DataAbort
191
192 .data_thumb_pushpop:
193         tst     r8, #1 << 10
194         beq     .data_unknown
195         and     r6, r8, #0x55                   @ hweight8(r8) + R bit
196         and     r9, r8, #0xaa
197         add     r6, r6, r9, lsr #1
198         and     r9, r6, #0xcc
199         and     r6, r6, #0x33
200         add     r6, r6, r9, lsr #2
201         movs    r7, r8, lsr #9                  @ C = r8 bit 8 (R bit)
202         adc     r6, r6, r6, lsr #4              @ high + low nibble + R bit
203         and     r6, r6, #15                     @ number of regs to transfer
204         ldr     r7, [r2, #13 << 2]
205         tst     r8, #1 << 11
206         addeq   r7, r7, r6, lsl #2              @ increment SP if PUSH
207         subne   r7, r7, r6, lsl #2              @ decrement SP if POP
208         str     r7, [r2, #13 << 2]
209         b       do_DataAbort
210
211 .data_thumb_ldmstm:
212         and     r6, r8, #0x55                   @ hweight8(r8)
213         and     r9, r8, #0xaa
214         add     r6, r6, r9, lsr #1
215         and     r9, r6, #0xcc
216         and     r6, r6, #0x33
217         add     r6, r6, r9, lsr #2
218         add     r6, r6, r6, lsr #4
219         and     r5, r8, #7 << 8
220         ldr     r7, [r2, r5, lsr #6]
221         and     r6, r6, #15                     @ number of regs to transfer
222         sub     r7, r7, r6, lsl #2              @ always decrement
223         str     r7, [r2, r5, lsr #6]
224         b       do_DataAbort