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