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