Merge master.kernel.org:/home/rmk/linux-2.6-arm
[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         mrc     p15, 0, r1, c5, c0, 0           @ get FSR
23         mrc     p15, 0, r0, c6, c0, 0           @ get FAR
24         bne     .data_thumb_abort
25         ldr     r8, [r2]                        @ read arm instruction
26         bic     r1, r1, #1 << 11 | 1 << 10      @ clear bits 11 and 10 of FSR
27         tst     r8, #1 << 20                    @ L = 1 -> write?
28         orreq   r1, r1, #1 << 11                @ yes.
29         and     r7, r8, #15 << 24
30         add     pc, pc, r7, lsr #22             @ Now branch to the relevant processing routine
31         nop
32
33 /* 0 */ b       .data_arm_lateldrhpost          @ ldrh  rd, [rn], #m/rm
34 /* 1 */ b       .data_arm_lateldrhpre           @ ldrh  rd, [rn, #m/rm]
35 /* 2 */ b       .data_unknown
36 /* 3 */ b       .data_unknown
37 /* 4 */ b       .data_arm_lateldrpostconst      @ ldr   rd, [rn], #m
38 /* 5 */ b       .data_arm_lateldrpreconst       @ ldr   rd, [rn, #m] 
39 /* 6 */ b       .data_arm_lateldrpostreg        @ ldr   rd, [rn], rm
40 /* 7 */ b       .data_arm_lateldrprereg         @ ldr   rd, [rn, rm]
41 /* 8 */ b       .data_arm_ldmstm                @ ldm*a rn, <rlist>
42 /* 9 */ b       .data_arm_ldmstm                @ ldm*b rn, <rlist>
43 /* a */ b       .data_unknown
44 /* b */ b       .data_unknown
45 /* c */ mov     pc, lr                          @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
46 /* d */ mov     pc, lr                          @ ldc   rd, [rn, #m]
47 /* e */ b       .data_unknown
48 /* f */
49 .data_unknown:  @ Part of jumptable
50         mov     r0, r2
51         mov     r1, r8
52         mov     r2, sp
53         bl      baddataabort
54         b       ret_from_exception
55
56 .data_arm_ldmstm:
57         tst     r8, #1 << 21                    @ check writeback bit
58         moveq   pc, lr                          @ no writeback -> no fixup
59         mov     r7, #0x11
60         orr     r7, r7, #0x1100
61         and     r6, r8, r7
62         and     r2, r8, r7, lsl #1
63         add     r6, r6, r2, lsr #1
64         and     r2, r8, r7, lsl #2
65         add     r6, r6, r2, lsr #2
66         and     r2, r8, r7, lsl #3
67         add     r6, r6, r2, 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     r5, r8, #15 << 16               @ Extract 'n' from instruction
72         ldr     r7, [sp, r5, 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, [sp, r5, lsr #14]           @ Put register 'Rn'
77         mov     pc, lr
78
79 .data_arm_lateldrhpre:
80         tst     r8, #1 << 21                    @ Check writeback bit
81         moveq   pc, lr                          @ No writeback -> no fixup
82 .data_arm_lateldrhpost:
83         and     r5, 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, r5, r6, lsr #4              @   combine nibbles } else
87         ldreq   r6, [sp, r5, lsl #2]            @ { load Rm value }
88 .data_arm_apply_r6_and_rn:
89         and     r5, r8, #15 << 16               @ Extract 'n' from instruction
90         ldr     r7, [sp, r5, 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, [sp, r5, lsr #14]           @ Put register 'Rn'
95         mov     pc, lr
96
97 .data_arm_lateldrpreconst:
98         tst     r8, #1 << 21                    @ check writeback bit
99         moveq   pc, lr                          @ no writeback -> no fixup
100 .data_arm_lateldrpostconst:
101         movs    r2, r8, lsl #20                 @ Get offset
102         moveq   pc, lr                          @ zero -> no fixup
103         and     r5, r8, #15 << 16               @ Extract 'n' from instruction
104         ldr     r7, [sp, r5, lsr #14]           @ Get register 'Rn'
105         tst     r8, #1 << 23                    @ Check U bit
106         subne   r7, r7, r2, lsr #20             @ Undo increment
107         addeq   r7, r7, r2, lsr #20             @ Undo decrement
108         str     r7, [sp, r5, lsr #14]           @ Put register 'Rn'
109         mov     pc, lr
110
111 .data_arm_lateldrprereg:
112         tst     r8, #1 << 21                    @ check writeback bit
113         moveq   pc, lr                          @ no writeback -> no fixup
114 .data_arm_lateldrpostreg:
115         and     r7, r8, #15                     @ Extract 'm' from instruction
116         ldr     r6, [sp, r7, lsl #2]            @ Get register 'Rm'
117         mov     r5, r8, lsr #7                  @ get shift count
118         ands    r5, r5, #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 r5                  @ 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 r5                  @ 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 r5                  @ 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 r5                  @ 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, [r2]                        @ 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 */ mov     pc, lr
171 /* 7 */ mov     pc, lr
172 /* 8 */ mov     pc, lr
173 /* 9 */ mov     pc, lr
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         moveq   pc, lr
184         tst     r8, #1 << 10                    @ If 'S' (signed) bit is set
185         movne   r1, #0                          @ it must be a load instr
186         mov     pc, lr
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     r2, r8, #0xaa
193         add     r6, r6, r2, lsr #1
194         and     r2, r6, #0xcc
195         and     r6, r6, #0x33
196         add     r6, r6, r2, 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, [sp, #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, [sp, #13 << 2]
205         mov     pc, lr
206
207 .data_thumb_ldmstm:
208         and     r6, r8, #0x55                   @ hweight8(r8)
209         and     r2, r8, #0xaa
210         add     r6, r6, r2, lsr #1
211         and     r2, r6, #0xcc
212         and     r6, r6, #0x33
213         add     r6, r6, r2, lsr #2
214         add     r6, r6, r6, lsr #4
215         and     r5, r8, #7 << 8
216         ldr     r7, [sp, r5, lsr #6]
217         and     r6, r6, #15                     @ number of regs to transfer
218         sub     r7, r7, r6, lsl #2              @ always decrement
219         str     r7, [sp, r5, lsr #6]
220         mov     pc, lr