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