Merge remote-tracking branches 'asoc/topic/inntel', 'asoc/topic/input', 'asoc/topic...
[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, r9-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         uaccess_disable ip                      @ disable userspace access
30         tst     r8, #1 << 20                    @ L = 1 -> write?
31         orreq   r1, r1, #1 << 11                @ yes.
32         and     r7, r8, #15 << 24
33         add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
34         nop
35
36 /* 0 */ b       .data_arm_lateldrhpost          @ ldrh  rd, [rn], #m/rm
37 /* 1 */ b       .data_arm_lateldrhpre           @ ldrh  rd, [rn, #m/rm]
38 /* 2 */ b       .data_unknown
39 /* 3 */ b       .data_unknown
40 /* 4 */ b       .data_arm_lateldrpostconst      @ ldr   rd, [rn], #m
41 /* 5 */ b       .data_arm_lateldrpreconst       @ ldr   rd, [rn, #m] 
42 /* 6 */ b       .data_arm_lateldrpostreg        @ ldr   rd, [rn], rm
43 /* 7 */ b       .data_arm_lateldrprereg         @ ldr   rd, [rn, rm]
44 /* 8 */ b       .data_arm_ldmstm                @ ldm*a rn, <rlist>
45 /* 9 */ b       .data_arm_ldmstm                @ ldm*b rn, <rlist>
46 /* a */ b       .data_unknown
47 /* b */ b       .data_unknown
48 /* c */ b       do_DataAbort                    @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
49 /* d */ b       do_DataAbort                    @ ldc   rd, [rn, #m]
50 /* e */ b       .data_unknown
51 /* f */ b       .data_unknown
52
53 .data_unknown_r9:
54         ldr     r9, [sp], #4
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         str     r9, [sp, #-4]!
64         mov     r7, #0x11
65         orr     r7, r7, #0x1100
66         and     r6, r8, r7
67         and     r9, r8, r7, lsl #1
68         add     r6, r6, r9, lsr #1
69         and     r9, r8, r7, lsl #2
70         add     r6, r6, r9, lsr #2
71         and     r9, r8, r7, lsl #3
72         add     r6, r6, r9, lsr #3
73         add     r6, r6, r6, lsr #8
74         add     r6, r6, r6, lsr #4
75         and     r6, r6, #15                     @ r6 = no. of registers to transfer.
76         and     r9, r8, #15 << 16               @ Extract 'n' from instruction
77         ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
78         tst     r8, #1 << 23                    @ Check U bit
79         subne   r7, r7, r6, lsl #2              @ Undo increment
80         addeq   r7, r7, r6, lsl #2              @ Undo decrement
81         str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
82         ldr     r9, [sp], #4
83         b       do_DataAbort
84
85 .data_arm_lateldrhpre:
86         tst     r8, #1 << 21                    @ Check writeback bit
87         beq     do_DataAbort                    @ No writeback -> no fixup
88 .data_arm_lateldrhpost:
89         str     r9, [sp, #-4]!
90         and     r9, r8, #0x00f                  @ get Rm / low nibble of immediate value
91         tst     r8, #1 << 22                    @ if (immediate offset)
92         andne   r6, r8, #0xf00                  @ { immediate high nibble
93         orrne   r6, r9, r6, lsr #4              @   combine nibbles } else
94         ldreq   r6, [r2, r9, lsl #2]            @ { load Rm value }
95 .data_arm_apply_r6_and_rn:
96         and     r9, r8, #15 << 16               @ Extract 'n' from instruction
97         ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
98         tst     r8, #1 << 23                    @ Check U bit
99         subne   r7, r7, r6                      @ Undo incrmenet
100         addeq   r7, r7, r6                      @ Undo decrement
101         str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
102         ldr     r9, [sp], #4
103         b       do_DataAbort
104
105 .data_arm_lateldrpreconst:
106         tst     r8, #1 << 21                    @ check writeback bit
107         beq     do_DataAbort                    @ no writeback -> no fixup
108 .data_arm_lateldrpostconst:
109         movs    r6, r8, lsl #20                 @ Get offset
110         beq     do_DataAbort                    @ zero -> no fixup
111         str     r9, [sp, #-4]!
112         and     r9, r8, #15 << 16               @ Extract 'n' from instruction
113         ldr     r7, [r2, r9, lsr #14]           @ Get register 'Rn'
114         tst     r8, #1 << 23                    @ Check U bit
115         subne   r7, r7, r6, lsr #20             @ Undo increment
116         addeq   r7, r7, r6, lsr #20             @ Undo decrement
117         str     r7, [r2, r9, lsr #14]           @ Put register 'Rn'
118         ldr     r9, [sp], #4
119         b       do_DataAbort
120
121 .data_arm_lateldrprereg:
122         tst     r8, #1 << 21                    @ check writeback bit
123         beq     do_DataAbort                    @ no writeback -> no fixup
124 .data_arm_lateldrpostreg:
125         and     r7, r8, #15                     @ Extract 'm' from instruction
126         ldr     r6, [r2, r7, lsl #2]            @ Get register 'Rm'
127         str     r9, [sp, #-4]!
128         mov     r9, r8, lsr #7                  @ get shift count
129         ands    r9, r9, #31
130         and     r7, r8, #0x70                   @ get shift type
131         orreq   r7, r7, #8                      @ shift count = 0
132         add     pc, pc, r7
133         nop
134
135         mov     r6, r6, lsl r9                  @ 0: LSL #!0
136         b       .data_arm_apply_r6_and_rn
137         b       .data_arm_apply_r6_and_rn       @ 1: LSL #0
138         nop
139         b       .data_unknown_r9                @ 2: MUL?
140         nop
141         b       .data_unknown_r9                @ 3: MUL?
142         nop
143         mov     r6, r6, lsr r9                  @ 4: LSR #!0
144         b       .data_arm_apply_r6_and_rn
145         mov     r6, r6, lsr #32                 @ 5: LSR #32
146         b       .data_arm_apply_r6_and_rn
147         b       .data_unknown_r9                @ 6: MUL?
148         nop
149         b       .data_unknown_r9                @ 7: MUL?
150         nop
151         mov     r6, r6, asr r9                  @ 8: ASR #!0
152         b       .data_arm_apply_r6_and_rn
153         mov     r6, r6, asr #32                 @ 9: ASR #32
154         b       .data_arm_apply_r6_and_rn
155         b       .data_unknown_r9                @ A: MUL?
156         nop
157         b       .data_unknown_r9                @ B: MUL?
158         nop
159         mov     r6, r6, ror r9                  @ C: ROR #!0
160         b       .data_arm_apply_r6_and_rn
161         mov     r6, r6, rrx                     @ D: RRX
162         b       .data_arm_apply_r6_and_rn
163         b       .data_unknown_r9                @ E: MUL?
164         nop
165         b       .data_unknown_r9                @ F: MUL?
166
167 .data_thumb_abort:
168         ldrh    r8, [r4]                        @ read instruction
169         uaccess_disable ip                      @ disable userspace access
170         tst     r8, #1 << 11                    @ L = 1 -> write?
171         orreq   r1, r1, #1 << 8                 @ yes
172         and     r7, r8, #15 << 12
173         add     pc, pc, r7, lsr #10             @ lookup in table
174         nop
175
176 /* 0 */ b       .data_unknown
177 /* 1 */ b       .data_unknown
178 /* 2 */ b       .data_unknown
179 /* 3 */ b       .data_unknown
180 /* 4 */ b       .data_unknown
181 /* 5 */ b       .data_thumb_reg
182 /* 6 */ b       do_DataAbort
183 /* 7 */ b       do_DataAbort
184 /* 8 */ b       do_DataAbort
185 /* 9 */ b       do_DataAbort
186 /* A */ b       .data_unknown
187 /* B */ b       .data_thumb_pushpop
188 /* C */ b       .data_thumb_ldmstm
189 /* D */ b       .data_unknown
190 /* E */ b       .data_unknown
191 /* F */ b       .data_unknown
192
193 .data_thumb_reg:
194         tst     r8, #1 << 9
195         beq     do_DataAbort
196         tst     r8, #1 << 10                    @ If 'S' (signed) bit is set
197         movne   r1, #0                          @ it must be a load instr
198         b       do_DataAbort
199
200 .data_thumb_pushpop:
201         tst     r8, #1 << 10
202         beq     .data_unknown
203         str     r9, [sp, #-4]!
204         and     r6, r8, #0x55                   @ hweight8(r8) + R bit
205         and     r9, r8, #0xaa
206         add     r6, r6, r9, lsr #1
207         and     r9, r6, #0xcc
208         and     r6, r6, #0x33
209         add     r6, r6, r9, lsr #2
210         movs    r7, r8, lsr #9                  @ C = r8 bit 8 (R bit)
211         adc     r6, r6, r6, lsr #4              @ high + low nibble + R bit
212         and     r6, r6, #15                     @ number of regs to transfer
213         ldr     r7, [r2, #13 << 2]
214         tst     r8, #1 << 11
215         addeq   r7, r7, r6, lsl #2              @ increment SP if PUSH
216         subne   r7, r7, r6, lsl #2              @ decrement SP if POP
217         str     r7, [r2, #13 << 2]
218         ldr     r9, [sp], #4
219         b       do_DataAbort
220
221 .data_thumb_ldmstm:
222         str     r9, [sp, #-4]!
223         and     r6, r8, #0x55                   @ hweight8(r8)
224         and     r9, r8, #0xaa
225         add     r6, r6, r9, lsr #1
226         and     r9, r6, #0xcc
227         and     r6, r6, #0x33
228         add     r6, r6, r9, lsr #2
229         add     r6, r6, r6, lsr #4
230         and     r9, r8, #7 << 8
231         ldr     r7, [r2, r9, lsr #6]
232         and     r6, r6, #15                     @ number of regs to transfer
233         sub     r7, r7, r6, lsl #2              @ always decrement
234         str     r7, [r2, r9, lsr #6]
235         ldr     r9, [sp], #4
236         b       do_DataAbort