Import 2.3.6
[davej-history.git] / arch / arm / kernel / entry-armo.S
blob3ca29cd2c5911ad36698bd7802880a6b82cb95aa
1 /*
2  * linux/arch/arm/kernel/entry-armo.S
3  *
4  * Copyright (C) 1995,1996,1997,1998 Russell King.
5  *
6  * Low-level vector interface routines
7  *
8  * Design issues:
9  *  - We have several modes that each vector can be called from,
10  *    each with its own set of registers.  On entry to any vector,
11  *    we *must* save the registers used in *that* mode.
12  *
13  *  - This code must be as fast as possible.
14  *
15  * There are a few restrictions on the vectors:
16  *  - the SWI vector cannot be called from *any* non-user mode
17  *
18  *  - the FP emulator is *never* called from *any* non-user mode undefined
19  *    instruction.
20  *
21  * Ok, so this file may be a mess, but its as efficient as possible while
22  * adhering to the above criteria.
23  */
24 #include <linux/linkage.h>
26 #include <asm/assembler.h>
27 #include <asm/errno.h>
28 #include <asm/hardware.h>
30 #include "../lib/constants.h"
32                 .text
34 @ Offsets into task structure
35 @ ---------------------------
37 #define STATE           0
38 #define COUNTER         4
39 #define PRIORITY        8
40 #define FLAGS           12
41 #define SIGPENDING      16
43 #define PF_TRACESYS     0x20
45 @ Bad Abort numbers
46 @ -----------------
48 #define BAD_PREFETCH    0
49 #define BAD_DATA        1
50 #define BAD_ADDREXCPTN  2
51 #define BAD_IRQ         3
52 #define BAD_UNDEFINSTR  4
54 @ OS version number used in SWIs
55 @  RISC OS is 0
56 @  RISC iX is 8
58 #define OS_NUMBER       9
61 @ Stack format (ensured by USER_* and SVC_*)
63 #define S_OLD_R0        64
64 #define S_PSR           60
65 #define S_PC            60
66 #define S_LR            56
67 #define S_SP            52
68 #define S_IP            48
69 #define S_FP            44
70 #define S_R10           40
71 #define S_R9            36
72 #define S_R8            32
73 #define S_R7            28
74 #define S_R6            24
75 #define S_R5            20
76 #define S_R4            16
77 #define S_R3            12
78 #define S_R2            8
79 #define S_R1            4
80 #define S_R0            0
82 #ifdef IOC_BASE
83 /* IOC / IOMD based hardware */
84                 .equ    ioc_base_high, IOC_BASE & 0xff000000
85                 .equ    ioc_base_low, IOC_BASE & 0x00ff0000
86                 .macro  disable_fiq
87                 mov     r12, #ioc_base_high
88                 .if     ioc_base_low
89                 orr     r12, r12, #ioc_base_low
90                 .endif
91                 strb    r12, [r12, #0x38]       @ Disable FIQ register
92                 .endm
94                 .macro  get_irqnr_and_base, irqnr, base
95                 mov     r4, #ioc_base_high              @ point at IOC
96                 .if     ioc_base_low
97                 orr     r4, r4, #ioc_base_low
98                 .endif
99                 ldrb    \irqnr, [r4, #0x24]             @ get high priority first
100                 adr     \base, irq_prio_h
101                 teq     \irqnr, #0
102                 ldreqb  \irqnr, [r4, #0x14]             @ get low priority
103                 adreq   \base, irq_prio_l
104                 .endm
107  * Interrupt table (incorporates priority)
108  */
109                 .macro  irq_prio_table
110 irq_prio_l:     .byte    0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
111                 .byte    4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
112                 .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
113                 .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
114                 .byte    6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
115                 .byte    6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
116                 .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
117                 .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
118                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
119                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
120                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
121                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
122                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
123                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
124                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
125                 .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
126 irq_prio_h:     .byte    0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
127                 .byte   12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
128                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
129                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
130                 .byte   14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
131                 .byte   14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
132                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
133                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
134                 .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
135                 .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
136                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
137                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
138                 .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
139                 .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
140                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
141                 .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
142                 .endm
143 #else
144 #error Unknown architecture
145 #endif
147 /*=============================================================================
148  * For entry-common.S
149  */
151                 .macro  save_user_regs
152                 str     r0, [sp, #-4]!
153                 str     lr, [sp, #-4]!
154                 sub     sp, sp, #15*4
155                 stmia   sp, {r0 - lr}^
156                 mov     r0, r0
157                 .endm
159                 .macro  restore_user_regs
160                 ldmia   sp, {r0 - lr}^
161                 mov     r0, r0
162                 add     sp, sp, #15*4
163                 ldr     lr, [sp], #8
164                 movs    pc, lr
165                 .endm
167                 .macro  mask_pc, rd, rm
168                 bic     \rd, \rm, #PCMASK
169                 .endm
171                 .macro  arm700_bug_check, instr, temp
172                 .endm
174                 .macro  enable_irqs, temp
175                 teqp    pc, #0x00000003
176                 .endm
178                 .macro  initialise_traps_extra
179                 .endm
181                 .macro  get_current_task, rd
182                 mov     \rd, sp, lsr #13
183                 mov     \rd, \rd, lsl #13
184                 .endm
186                 /*
187                  * Like adr, but force SVC mode (if required)
188                  */
189                 .macro  adrsvc, cond, reg, label
190                 adr\cond        \reg, \label
191                 orr\cond        \reg, \reg, #0x08000003
192                 .endm
194 #if 0
196  * Uncomment these if you wish to get more debugging into about data aborts.
197  */
198 #define FAULT_CODE_LDRSTRPOST   0x80
199 #define FAULT_CODE_LDRSTRPRE    0x40
200 #define FAULT_CODE_LDRSTRREG    0x20
201 #define FAULT_CODE_LDMSTM       0x10
202 #define FAULT_CODE_LDCSTC       0x08
203 #endif
204 #define FAULT_CODE_PREFETCH     0x04
205 #define FAULT_CODE_WRITE        0x02
206 #define FAULT_CODE_USER         0x01
209 #define SVC_SAVE_ALL                            \
210                 str     sp, [sp, #-16]!         ;\
211                 str     lr, [sp, #8]            ;\
212                 str     lr, [sp, #4]            ;\
213                 stmfd   sp!, {r0 - r12}         ;\
214                 mov     r0, #-1                 ;\
215                 str     r0, [sp, #S_OLD_R0]     ;\
216                 mov     fp, #0
218 #define SVC_IRQ_SAVE_ALL                        \
219                 str     sp, [sp, #-16]!         ;\
220                 str     lr, [sp, #4]            ;\
221                 ldr     lr, .LCirq              ;\
222                 ldr     lr, [lr]                ;\
223                 str     lr, [sp, #8]            ;\
224                 stmfd   sp!, {r0 - r12}         ;\
225                 mov     r0, #-1                 ;\
226                 str     r0, [sp, #S_OLD_R0]     ;\
227                 mov     fp, #0
229 #define USER_RESTORE_ALL                        \
230                 ldmia   sp, {r0 - lr}^          ;\
231                 mov     r0, r0                  ;\
232                 add     sp, sp, #15*4           ;\
233                 ldr     lr, [sp], #8            ;\
234                 movs    pc, lr
236 #define SVC_RESTORE_ALL                         \
237                 ldmfd   sp, {r0 - pc}^
238                 
239 /*=============================================================================
240  * Undefined FIQs
241  *-----------------------------------------------------------------------------
242  */
243 _unexp_fiq:     ldr     sp, .LCfiq
244                 mov     r12, #IOC_BASE
245                 strb    r12, [r12, #0x38]       @ Disable FIQ register
246                 teqp    pc, #0x0c000003
247                 mov     r0, r0
248                 stmfd   sp!, {r0 - r3, ip, lr}
249                 adr     r0, Lfiqmsg
250                 bl      SYMBOL_NAME(printk)
251                 ldmfd   sp!, {r0 - r3, ip, lr}
252                 teqp    pc, #0x0c000001
253                 mov     r0, r0
254                 movs    pc, lr
256 Lfiqmsg:        .ascii  "*** Unexpeced FIQ\n\0"
257                 .align
259 .LCfiq:         .word   __temp_fiq
260 .LCirq:         .word   __temp_irq
262 /*=============================================================================
263  * Undefined instruction handler
264  *-----------------------------------------------------------------------------
265  * Handles floating point instructions
266  */
267 vector_undefinstr:
268                 tst     lr,#3
269                 bne     __und_svc
270                 save_user_regs
271                 mov     fp, #0
272                 teqp    pc, #I_BIT | MODE_SVC
273 .Lbug_undef:
274                 ldr     r4, .LC2
275                 ldr     pc, [r4]                        @ Call FP module USR entry point
277                 .globl  SYMBOL_NAME(fpundefinstr)
278 SYMBOL_NAME(fpundefinstr):                              @ Called by FP module on undefined instr
279                 mov     r0, lr
280                 mov     r1, sp
281                 teqp    pc, #MODE_SVC
282                 bl      SYMBOL_NAME(do_undefinstr)
283                 b       ret_from_exception              @ Normal FP exit
285 __und_svc:      SVC_SAVE_ALL                            @ Non-user mode
286                 mask_pc r0, lr
287                 and     r2, lr, #3
288                 sub     r0, r0, #4
289                 mov     r1, sp
290                 bl      SYMBOL_NAME(do_undefinstr)
291                 SVC_RESTORE_ALL
293 /* We get here if an undefined instruction happens and the floating
294  * point emulator is not present.  If the offending instruction was
295  * a WFS, we just perform a normal return as if we had emulated the
296  * operation.  This is a hack to allow some basic userland binaries
297  * to run so that the emulator module proper can be loaded. --philb
298  */
299 fpe_not_present:
300                 adr     r10, wfs_mask_data
301                 ldmia   r10, {r4, r5, r6, r7, r8}
302                 ldr     r10, [sp, #S_PC]                @ Load PC
303                 sub     r10, r10, #4
304                 mask_pc r10, r10
305                 ldrt    r10, [r10]                      @ get instruction
306                 and     r5, r10, r5
307                 teq     r5, r4                          @ Is it WFS?
308                 beq     ret_from_exception
309                 and     r5, r10, r8
310                 teq     r5, r6                          @ Is it LDF/STF on sp or fp?
311                 teqne   r5, r7
312                 bne     fpundefinstr
313                 tst     r10, #0x00200000                @ Does it have WB
314                 beq     ret_from_exception
315                 and     r4, r10, #255                   @ get offset
316                 and     r6, r10, #0x000f0000
317                 tst     r10, #0x00800000                @ +/-
318                 rsbeq   r4, r4, #0
319                 ldr     r5, [sp, r6, lsr #14]           @ Load reg
320                 add     r5, r5, r4, lsl #2
321                 str     r5, [sp, r6, lsr #14]           @ Save reg
322                 b       ret_from_exception
324 wfs_mask_data:  .word   0x0e200110                      @ WFS
325                 .word   0x0fff0fff
326                 .word   0x0d0d0100                      @ LDF [sp]/STF [sp]
327                 .word   0x0d0b0100                      @ LDF [fp]/STF [fp]
328                 .word   0x0f0f0f00
330 .LC2:           .word   SYMBOL_NAME(fp_enter)
332 /*=============================================================================
333  * Prefetch abort handler
334  *-----------------------------------------------------------------------------
335  */
337 vector_prefetch:
338                 sub     lr, lr, #4
339                 tst     lr, #3
340                 bne     __pabt_invalid
341                 save_user_regs
342                 teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
343                 mask_pc r0, lr                  @ Address of abort
344                 mov     r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code
345                 mov     r2, sp                  @ Tasks registers
346                 bl      SYMBOL_NAME(do_PrefetchAbort)
347                 teq     r0, #0                  @ If non-zero, we believe this abort..
348                 bne     ret_from_sys_call
349 #ifdef DEBUG_UNDEF
350                 adr     r0, t
351                 bl      SYMBOL_NAME(printk)
352 #endif
353                 ldr     lr, [sp,#S_PC]          @ program to test this on.  I think its
354                 b       .Lbug_undef             @ broken at the moment though!)
356 __pabt_invalid: SVC_SAVE_ALL
357                 mov     r0, sp                          @ Prefetch aborts are definitely *not*
358                 mov     r1, #BAD_PREFETCH               @ allowed in non-user modes.  We cant
359                 and     r2, lr, #3                      @ recover from this problem.
360                 b       SYMBOL_NAME(bad_mode)
362 #ifdef DEBUG_UNDEF
363 t:              .ascii "*** undef ***\r\n\0"
364                 .align
365 #endif
367 /*=============================================================================
368  * Address exception handler
369  *-----------------------------------------------------------------------------
370  * These aren't too critical.
371  * (they're not supposed to happen).
372  * In order to debug the reason for address exceptions in non-user modes,
373  * we have to obtain all the registers so that we can see what's going on.
374  */
376 vector_addrexcptn:
377                 sub     lr, lr, #8
378                 tst     lr, #3
379                 bne     Laddrexcptn_not_user
380                 save_user_regs
381                 teq     pc, #0x00000003
382                 mask_pc r0, lr                  @ Point to instruction
383                 mov     r1, sp                  @ Point to registers
384                 mov     r2, #0x400
385                 mov     lr, pc
386                 bl      SYMBOL_NAME(do_excpt)
387                 b       ret_from_exception
389 Laddrexcptn_not_user:
390                 SVC_SAVE_ALL
391                 and     r2, lr, #3
392                 teq     r2, #3
393                 bne     Laddrexcptn_illegal_mode
394                 teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
395                 mask_pc r0, lr
396                 mov     r1, sp
397                 orr     r2, r2, #0x400
398                 bl      SYMBOL_NAME(do_excpt)
399                 ldmia   sp, {r0 - lr}           @ I cant remember the reason I changed this...
400                 add     sp, sp, #15*4
401                 movs    pc, lr
403 Laddrexcptn_illegal_mode:
404                 mov     r0, sp
405                 str     lr, [sp, #-4]!
406                 orr     r1, r2, #0x0c000000
407                 teqp    r1, #0                  @ change into mode (wont be user mode)
408                 mov     r0, r0
409                 mov     r1, r8                  @ Any register from r8 - r14 can be banked
410                 mov     r2, r9
411                 mov     r3, r10
412                 mov     r4, r11
413                 mov     r5, r12
414                 mov     r6, r13
415                 mov     r7, r14
416                 teqp    pc, #0x04000003         @ back to svc
417                 mov     r0, r0
418                 stmfd   sp!, {r1-r7}
419                 ldmia   r0, {r0-r7}
420                 stmfd   sp!, {r0-r7}
421                 mov     r0, sp
422                 mov     r1, #BAD_ADDREXCPTN
423                 b       SYMBOL_NAME(bad_mode)
425 /*=============================================================================
426  * Interrupt (IRQ) handler
427  *-----------------------------------------------------------------------------
428  * Note: if in user mode, then *no* kernel routine is running, so do not have
429  *       to save svc lr
430  * (r13 points to irq temp save area)
431  */
433 vector_IRQ:     ldr     r13, .LCirq                     @ I will leave this one in just in case...
434                 sub     lr, lr, #4
435                 str     lr, [r13]
436                 tst     lr, #3
437                 bne     __irq_svc
438                 teqp    pc, #0x08000003
439                 mov     r0, r0
440                 ldr     lr, .LCirq
441                 ldr     lr, [lr]
442                 save_user_regs
444 1:              get_irqnr_and_base r6, r5
445                 teq     r6, #0
446                 ldrneb  r0, [r5, r6]                    @ get IRQ number
447                 movne   r1, sp
448                 @
449                 @ routine called with r0 = irq number, r1 = struct pt_regs *
450                 @
451                 adr     lr, 1b
452                 orr     lr, lr, #0x08000003             @ Force SVC
453                 bne     do_IRQ
454                 b       ret_with_reschedule
456                 irq_prio_table
458 __irq_svc:      teqp    pc, #0x08000003
459                 mov     r0, r0
460                 SVC_IRQ_SAVE_ALL
461                 and     r2, lr, #3
462                 teq     r2, #3
463                 bne     __irq_invalid
464 1:              get_irqnr_and_base r6, r5
465                 teq     r6, #0
466                 ldrneb  r0, [r5, r6]                    @ get IRQ number
467                 movne   r1, sp
468                 @
469                 @ routine called with r0 = irq number, r1 = struct pt_regs *
470                 @
471                 adr     lr, 1b
472                 orr     lr, lr, #0x08000003             @ Force SVC
473                 bne     do_IRQ                          @ Returns to 1b
474                 SVC_RESTORE_ALL
476 __irq_invalid:  mov     r0, sp
477                 mov     r1, #BAD_IRQ
478                 b       SYMBOL_NAME(bad_mode)
480 /*=============================================================================
481  * Data abort handler code
482  *-----------------------------------------------------------------------------
484  * This handles both exceptions from user and SVC modes, computes the address
485  *  range of the problem, and does any correction that is required.  It then
486  *  calls the kernel data abort routine.
488  * This is where I wish that the ARM would tell you which address aborted.
489  */
491 vector_data:    sub     lr, lr, #8              @ Correct lr
492                 tst     lr, #3
493                 bne     Ldata_not_user
494                 save_user_regs
495                 teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
496                 mask_pc r0, lr
497                 mov     r2, #FAULT_CODE_USER
498                 bl      Ldata_do
499                 b       ret_from_exception
501 Ldata_not_user:
502                 SVC_SAVE_ALL
503                 and     r2, lr, #3
504                 teq     r2, #3
505                 bne     Ldata_illegal_mode
506                 tst     lr, #0x08000000
507                 teqeqp  pc, #0x00000003         @ NOT a problem - doesnt change mode
508                 mask_pc r0, lr
509                 mov     r2, #0
510                 bl      Ldata_do
511                 SVC_RESTORE_ALL
513 Ldata_illegal_mode:
514                 mov     r0, sp
515                 mov     r1, #BAD_DATA
516                 b       SYMBOL_NAME(bad_mode)
518 Ldata_do:       mov     r3, sp
519                 ldr     r4, [r0]                @ Get instruction
520                 tst     r4, #1 << 20            @ Check to see if it is a write instruction
521                 orreq   r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
522                 mov     r1, r4, lsr #22         @ Now branch to the relevent processing routine
523                 and     r1, r1, #15 << 2
524                 add     pc, pc, r1
525                 movs    pc, lr
526                 b       Ldata_unknown
527                 b       Ldata_unknown
528                 b       Ldata_unknown
529                 b       Ldata_unknown
530                 b       Ldata_ldrstr_post       @ ldr   rd, [rn], #m
531                 b       Ldata_ldrstr_numindex   @ ldr   rd, [rn, #m]    @ RegVal
532                 b       Ldata_ldrstr_post       @ ldr   rd, [rn], rm
533                 b       Ldata_ldrstr_regindex   @ ldr   rd, [rn, rm]
534                 b       Ldata_ldmstm            @ ldm*a rn, <rlist>
535                 b       Ldata_ldmstm            @ ldm*b rn, <rlist>
536                 b       Ldata_unknown
537                 b       Ldata_unknown
538                 b       Ldata_ldrstr_post       @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
539                 b       Ldata_ldcstc_pre        @ ldc   rd, [rn, #m]
540                 b       Ldata_unknown
541 Ldata_unknown:  @ Part of jumptable
542                 mov     r0, r1
543                 mov     r1, r4
544                 mov     r2, r3
545         mov r3, lr
546                 b       baddataabort
548 Ldata_ldrstr_post:
549                 mov     r0, r4, lsr #14         @ Get Rn
550                 and     r0, r0, #15 << 2        @ Mask out reg.
551                 teq     r0, #15 << 2
552                 ldr     r0, [r3, r0]            @ Get register
553                 biceq   r0, r0, #PCMASK
554                 mov     r1, r0
555 #ifdef FAULT_CODE_LDRSTRPOST
556                 orr     r2, r2, #FAULT_CODE_LDRSTRPOST
557 #endif
558                 b       SYMBOL_NAME(do_DataAbort)
560 Ldata_ldrstr_numindex:
561                 mov     r0, r4, lsr #14         @ Get Rn
562                 and     r0, r0, #15 << 2        @ Mask out reg.
563                 teq     r0, #15 << 2
564                 ldr     r0, [r3, r0]            @ Get register
565                 biceq   r0, r0, #PCMASK
566                 mov     r1, r4, lsl #20
567                 tst     r4, #1 << 23
568                 addne   r0, r0, r1, lsr #20
569                 subeq   r0, r0, r1, lsr #20
570                 mov     r1, r0
571 #ifdef FAULT_CODE_LDRSTRPRE
572                 orr     r2, r2, #FAULT_CODE_LDRSTRPRE
573 #endif
574                 b       SYMBOL_NAME(do_DataAbort)
576 Ldata_ldrstr_regindex:
577                 mov     r0, r4, lsr #14         @ Get Rn
578                 and     r0, r0, #15 << 2        @ Mask out reg.
579                 teq     r0, #15 << 2
580                 ldr     r0, [r3, r0]            @ Get register
581                 biceq   r0, r0, #PCMASK
582                 and     r7, r4, #15
583                 teq     r7, #15                 @ Check for PC
584                 ldr     r7, [r3, r7, lsl #2]    @ Get Rm
585                 biceq   r7, r7, #PCMASK
586                 and     r8, r4, #0x60           @ Get shift types
587                 mov     r9, r4, lsr #7          @ Get shift amount
588                 and     r9, r9, #31
589                 teq     r8, #0
590                 moveq   r7, r7, lsl r9
591                 teq     r8, #0x20               @ LSR shift
592                 moveq   r7, r7, lsr r9
593                 teq     r8, #0x40               @ ASR shift
594                 moveq   r7, r7, asr r9
595                 teq     r8, #0x60               @ ROR shift
596                 moveq   r7, r7, ror r9
597                 tst     r4, #1 << 23
598                 addne   r0, r0, r7
599                 subeq   r0, r0, r7              @ Apply correction
600                 mov     r1, r0
601 #ifdef FAULT_CODE_LDRSTRREG
602                 orr     r2, r2, #FAULT_CODE_LDRSTRREG
603 #endif
604                 b       SYMBOL_NAME(do_DataAbort)
606 Ldata_ldmstm:
607                 mov     r7, #0x11
608                 orr     r7, r7, r7, lsl #8
609                 and     r0, r4, r7
610                 and     r1, r4, r7, lsl #1
611                 add     r0, r0, r1, lsr #1
612                 and     r1, r4, r7, lsl #2
613                 add     r0, r0, r1, lsr #2
614                 and     r1, r4, r7, lsl #3
615                 add     r0, r0, r1, lsr #3
616                 add     r0, r0, r0, lsr #8
617                 add     r0, r0, r0, lsr #4
618                 and     r7, r0, #15             @ r7 = no. of registers to transfer.
619                 mov     r5, r4, lsr #14         @ Get Rn
620                 and     r5, r5, #15 << 2
621                 ldr     r0, [r3, r5]            @ Get reg
622                 eor     r6, r4, r4, lsl #2
623                 tst     r6, #1 << 23            @ Check inc/dec ^ writeback
624                 rsbeq   r7, r7, #0
625                 add     r7, r0, r7, lsl #2      @ Do correction (signed)
626                 subne   r1, r7, #1
627                 subeq   r1, r0, #1
628                 moveq   r0, r7
629                 tst     r4, #1 << 21            @ Check writeback
630                 strne   r7, [r3, r5]
631                 eor     r6, r4, r4, lsl #1
632                 tst     r6, #1 << 24            @ Check Pre/Post ^ inc/dec
633                 addeq   r0, r0, #4
634                 addeq   r1, r1, #4
635                 teq     r5, #15*4               @ CHECK FOR PC
636                 biceq   r1, r1, #PCMASK
637                 biceq   r0, r0, #PCMASK
638 #ifdef FAULT_CODE_LDMSTM
639                 orr     r2, r2, #FAULT_CODE_LDMSTM
640 #endif
641                 b       SYMBOL_NAME(do_DataAbort)
643 Ldata_ldcstc_pre:
644                 mov     r0, r4, lsr #14         @ Get Rn
645                 and     r0, r0, #15 << 2        @ Mask out reg.
646                 teq     r0, #15 << 2
647                 ldr     r0, [r3, r0]            @ Get register
648                 biceq   r0, r0, #PCMASK
649                 mov     r1, r4, lsl #24         @ Get offset
650                 tst     r4, #1 << 23
651                 addne   r0, r0, r1, lsr #24
652                 subeq   r0, r0, r1, lsr #24
653                 mov     r1, r0
654 #ifdef FAULT_CODE_LDCSTC
655                 orr     r2, r2, #FAULT_CODE_LDCSTC
656 #endif
657                 b       SYMBOL_NAME(do_DataAbort)
659 #include "entry-common.S"
661                 .data
663 __temp_irq:     .word   0                               @ saved lr_irq
664 __temp_fiq:     .space  128