patch-2.1.80 linux/arch/arm/kernel/entry-armo.S
Next file: linux/arch/arm/kernel/entry-armv.S
Previous file: linux/arch/arm/kernel/ecard.c
Back to the patch index
Back to the overall index
- Lines: 644
- Date:
Tue Jan 20 16:39:41 1998
- Orig file:
v2.1.79/linux/arch/arm/kernel/entry-armo.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.79/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S
@@ -0,0 +1,643 @@
+/*
+ * linux/arch/arm/kernel/entry-armo.S
+ *
+ * Copyright (C) 1995,1996,1997,1998 Russell King.
+ *
+ * Low-level vector interface routines
+ *
+ * Design issues:
+ * - We have several modes that each vector can be called from,
+ * each with its own set of registers. On entry to any vector,
+ * we *must* save the registers used in *that* mode.
+ *
+ * - This code must be as fast as possible.
+ *
+ * There are a few restrictions on the vectors:
+ * - the SWI vector cannot be called from *any* non-user mode
+ *
+ * - the FP emulator is *never* called from *any* non-user mode undefined
+ * instruction.
+ *
+ * Ok, so this file may be a mess, but its as efficient as possible while
+ * adhering to the above criteria.
+ */
+#include <linux/autoconf.h>
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/hardware.h>
+
+#include "../lib/constants.h"
+
+ .text
+
+@ Offsets into task structure
+@ ---------------------------
+@
+#define STATE 0
+#define COUNTER 4
+#define PRIORITY 8
+#define FLAGS 12
+#define SIGPENDING 16
+
+#define PF_TRACESYS 0x20
+
+@ Bad Abort numbers
+@ -----------------
+@
+#define BAD_PREFETCH 0
+#define BAD_DATA 1
+#define BAD_ADDREXCPTN 2
+#define BAD_IRQ 3
+#define BAD_UNDEFINSTR 4
+
+@ OS version number used in SWIs
+@ RISC OS is 0
+@ RISC iX is 8
+@
+#define OS_NUMBER 9
+
+@
+@ Stack format (ensured by USER_* and SVC_*)
+@
+#define S_OLD_R0 64
+#define S_PSR 60
+#define S_PC 60
+#define S_LR 56
+#define S_SP 52
+#define S_IP 48
+#define S_FP 44
+#define S_R10 40
+#define S_R9 36
+#define S_R8 32
+#define S_R7 28
+#define S_R6 24
+#define S_R5 20
+#define S_R4 16
+#define S_R3 12
+#define S_R2 8
+#define S_R1 4
+#define S_R0 0
+
+#ifdef IOC_BASE
+/* IOC / IOMD based hardware */
+ .equ ioc_base_high, IOC_BASE & 0xff000000
+ .equ ioc_base_low, IOC_BASE & 0x00ff0000
+ .macro disable_fiq
+ mov r12, #ioc_base_high
+ .if ioc_base_low
+ orr r12, r12, #ioc_base_low
+ .endif
+ strb r12, [r12, #0x38] @ Disable FIQ register
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, base
+ mov r4, #ioc_base_high @ point at IOC
+ .if ioc_base_low
+ orr r4, r4, #ioc_base_low
+ .endif
+ ldrb \irqnr, [r4, #0x24] @ get high priority first
+ adr \base, irq_prio_h
+ teq \irqnr, #0
+ ldreqb \irqnr, [r4, #0x14] @ get low priority
+ adreq \base, irq_prio_l
+ .endm
+
+/*
+ * Interrupt table (incorporates priority)
+ */
+ .macro irq_prio_table
+irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+ .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+ .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+ .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+ .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+ .endm
+#else
+#error Unknown architecture
+#endif
+
+/*=============================================================================
+ * For entry-common.S
+ */
+
+ .macro save_user_regs
+ str r0, [sp, #-4]!
+ str lr, [sp, #-4]!
+ sub sp, sp, #15*4
+ stmia sp, {r0 - lr}^
+ mov r0, r0
+ .endm
+
+ .macro restore_user_regs
+ ldmia sp, {r0 - lr}^
+ mov r0, r0
+ add sp, sp, #15*4
+ ldr lr, [sp], #8
+ movs pc, lr
+ .endm
+
+ .macro mask_pc, rd, rm
+ bic \rd, \rm, #PCMASK
+ .endm
+
+ .macro arm700_bug_check, instr, temp
+ .endm
+
+ .macro enable_irqs, temp
+ teqp pc, #0x00000003
+ .endm
+
+ .macro initialise_traps_extra
+ .endm
+
+ .macro get_current_task, rd
+ mov \rd, sp, lsr #13
+ mov \rd, \rd, lsl #13
+ .endm
+
+ /*
+ * Like adr, but force SVC mode (if required)
+ */
+ .macro adrsvc, cond, reg, label
+ adr\cond \reg, \label
+ orr\cond \reg, \reg, #3
+ .endm
+
+#if 0
+/*
+ * Uncomment these if you wish to get more debugging into about data aborts.
+ */
+#define FAULT_CODE_LDRSTRPOST 0x80
+#define FAULT_CODE_LDRSTRPRE 0x40
+#define FAULT_CODE_LDRSTRREG 0x20
+#define FAULT_CODE_LDMSTM 0x10
+#define FAULT_CODE_LDCSTC 0x08
+#endif
+#define FAULT_CODE_PREFETCH 0x04
+#define FAULT_CODE_WRITE 0x02
+#define FAULT_CODE_USER 0x01
+
+
+#define SVC_SAVE_ALL \
+ str sp, [sp, #-16]! ;\
+ str lr, [sp, #8] ;\
+ str lr, [sp, #4] ;\
+ stmfd sp!, {r0 - r12} ;\
+ mov r0, #-1 ;\
+ str r0, [sp, #S_OLD_R0] ;\
+ mov fp, #0
+
+#define SVC_IRQ_SAVE_ALL \
+ str sp, [sp, #-16]! ;\
+ str lr, [sp, #4] ;\
+ ldr lr, .LCirq ;\
+ ldr lr, [lr] ;\
+ str lr, [sp, #8] ;\
+ stmfd sp!, {r0 - r12} ;\
+ mov r0, #-1 ;\
+ str r0, [sp, #S_OLD_R0] ;\
+ mov fp, #0
+
+#define USER_RESTORE_ALL \
+ ldmia sp, {r0 - lr}^ ;\
+ mov r0, r0 ;\
+ add sp, sp, #15*4 ;\
+ ldr lr, [sp], #8 ;\
+ movs pc, lr
+
+#define SVC_RESTORE_ALL \
+ ldmfd sp, {r0 - pc}^
+
+/*=============================================================================
+ * Undefined FIQs
+ *-----------------------------------------------------------------------------
+ */
+_unexp_fiq: ldr sp, .LCfiq
+ mov r12, #IOC_BASE
+ strb r12, [r12, #0x38] @ Disable FIQ register
+ teqp pc, #0x0c000003
+ mov r0, r0
+ stmfd sp!, {r0 - r3, ip, lr}
+ adr r0, Lfiqmsg
+ bl SYMBOL_NAME(printk)
+ ldmfd sp!, {r0 - r3, ip, lr}
+ teqp pc, #0x0c000001
+ mov r0, r0
+ movs pc, lr
+
+Lfiqmsg: .ascii "*** Unexpeced FIQ\n\0"
+ .align
+
+.LCfiq: .word __temp_fiq
+.LCirq: .word __temp_irq
+
+/*=============================================================================
+ * Undefined instruction handler
+ *-----------------------------------------------------------------------------
+ * Handles floating point instructions
+ */
+vector_undefinstr:
+ tst lr,#3
+ bne __und_svc
+ save_user_regs
+ mov fp, #0
+ teqp pc, #I_BIT | MODE_SVC
+.Lbug_undef:
+ adr r1, .LC2
+ ldmia r1, {r1, r4}
+ ldr r1, [r1]
+ get_current_task r2
+ teq r1, r2
+ stmnefd sp!, {ip, lr}
+ blne SYMBOL_NAME(math_state_restore)
+ ldmnefd sp!, {ip, lr}
+ ldr pc, [r4] @ Call FP module USR entry point
+
+ .globl SYMBOL_NAME(fpundefinstr)
+SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr
+SYMBOL_NAME(fpundefinstrsvc):
+ mov r0, lr
+ mov r1, sp
+ teqp pc, #MODE_SVC
+ bl SYMBOL_NAME(do_undefinstr)
+ b ret_from_exception @ Normal FP exit
+
+__und_svc: SVC_SAVE_ALL @ Non-user mode
+ mask_pc r0, lr
+ and r2, lr, #3
+ sub r0, r0, #4
+ mov r1, sp
+ bl SYMBOL_NAME(do_undefinstr)
+ SVC_RESTORE_ALL
+
+.LC2: .word SYMBOL_NAME(last_task_used_math)
+ .word SYMBOL_NAME(fp_enter)
+
+/*=============================================================================
+ * Prefetch abort handler
+ *-----------------------------------------------------------------------------
+ */
+
+vector_prefetch:
+ sub lr, lr, #4
+ tst lr, #3
+ bne __pabt_invalid
+ save_user_regs
+ teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
+ mask_pc r0, lr @ Address of abort
+ mov r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code
+ mov r2, sp @ Tasks registers
+ bl SYMBOL_NAME(do_PrefetchAbort)
+ teq r0, #0 @ If non-zero, we believe this abort..
+ bne ret_from_sys_call
+#ifdef DEBUG_UNDEF
+ adr r0, t
+ bl SYMBOL_NAME(printk)
+#endif
+ ldr lr, [sp,#S_PC] @ program to test this on. I think its
+ b .Lbug_undef @ broken at the moment though!)
+
+__pabt_invalid: SVC_SAVE_ALL
+ mov r0, sp @ Prefetch aborts are definitely *not*
+ mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
+ and r2, lr, #3 @ recover from this problem.
+ b SYMBOL_NAME(bad_mode)
+
+#ifdef DEBUG_UNDEF
+t: .ascii "*** undef ***\r\n\0"
+ .align
+#endif
+
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen).
+ * In order to debug the reason for address exceptions in non-user modes,
+ * we have to obtain all the registers so that we can see what's going on.
+ */
+
+vector_addrexcptn:
+ sub lr, lr, #8
+ tst lr, #3
+ bne Laddrexcptn_not_user
+ save_user_regs
+ teq pc, #0x00000003
+ mask_pc r0, lr @ Point to instruction
+ mov r1, sp @ Point to registers
+ mov r2, #0x400
+ mov lr, pc
+ bl SYMBOL_NAME(do_excpt)
+ b ret_from_exception
+
+Laddrexcptn_not_user:
+ SVC_SAVE_ALL
+ and r2, lr, #3
+ teq r2, #3
+ bne Laddrexcptn_illegal_mode
+ teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
+ mask_pc r0, lr
+ mov r1, sp
+ orr r2, r2, #0x400
+ bl SYMBOL_NAME(do_excpt)
+ ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
+ add sp, sp, #15*4
+ movs pc, lr
+
+Laddrexcptn_illegal_mode:
+ mov r0, sp
+ str lr, [sp, #-4]!
+ orr r1, r2, #0x0c000000
+ teqp r1, #0 @ change into mode (wont be user mode)
+ mov r0, r0
+ mov r1, r8 @ Any register from r8 - r14 can be banked
+ mov r2, r9
+ mov r3, r10
+ mov r4, r11
+ mov r5, r12
+ mov r6, r13
+ mov r7, r14
+ teqp pc, #0x04000003 @ back to svc
+ mov r0, r0
+ stmfd sp!, {r1-r7}
+ ldmia r0, {r0-r7}
+ stmfd sp!, {r0-r7}
+ mov r0, sp
+ mov r1, #BAD_ADDREXCPTN
+ b SYMBOL_NAME(bad_mode)
+
+/*=============================================================================
+ * Interrupt (IRQ) handler
+ *-----------------------------------------------------------------------------
+ * Note: if in user mode, then *no* kernel routine is running, so dont have
+ * to save svc lr
+ * (r13 points to irq temp save area)
+ */
+
+vector_IRQ: ldr r13, .LCirq @ Ill leave this one in just in case...
+ sub lr, lr, #4
+ str lr, [r13]
+ tst lr, #3
+ bne __irq_svc
+ teqp pc, #0x08000003
+ mov r0, r0
+ ldr lr, .LCirq
+ ldr lr, [lr]
+ save_user_regs
+
+1: get_irqnr_and_base r6, r5
+ teq r6, #0
+ ldrneb r0, [r5, r6] @ get IRQ number
+ movne r1, sp
+ @
+ @ routine called with r0 = irq number, r1 = struct pt_regs *
+ @
+ adr lr, 1b
+ orr lr, lr, #3 @ Force SVC
+ bne do_IRQ
+ b ret_with_reschedule
+
+ irq_prio_table
+
+__irq_svc: teqp pc, #0x08000003
+ mov r0, r0
+ SVC_IRQ_SAVE_ALL
+ and r2, lr, #3
+ teq r2, #3
+ bne __irq_invalid
+1: get_irqnr_and_base r6, r5
+ teq r6, #0
+ ldrneb r0, [r5, r6] @ get IRQ number
+ movne r1, sp
+ @
+ @ routine called with r0 = irq number, r1 = struct pt_regs *
+ @
+ adr lr, 1b
+ orr lr, lr, #3 @ Force SVC
+ bne do_IRQ @ Returns to 1b
+ SVC_RESTORE_ALL
+
+__irq_invalid: mov r0, sp
+ mov r1, #BAD_IRQ
+ b SYMBOL_NAME(bad_mode)
+
+/*=============================================================================
+ * Data abort handler code
+ *-----------------------------------------------------------------------------
+ *
+ * This handles both exceptions from user and SVC modes, computes the address
+ * range of the problem, and does any correction that is required. It then
+ * calls the kernel data abort routine.
+ *
+ * This is where I wish that the ARM would tell you which address aborted.
+ */
+
+vector_data: sub lr, lr, #8 @ Correct lr
+ tst lr, #3
+ bne Ldata_not_user
+ save_user_regs
+ teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
+ mask_pc r0, lr
+ mov r2, #FAULT_CODE_USER
+ bl Ldata_do
+ b ret_from_exception
+
+Ldata_not_user:
+ SVC_SAVE_ALL
+ and r2, lr, #3
+ teq r2, #3
+ bne Ldata_illegal_mode
+ tst lr, #0x08000000
+ teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode
+ mask_pc r0, lr
+ mov r2, #0
+ bl Ldata_do
+ SVC_RESTORE_ALL
+
+Ldata_illegal_mode:
+ mov r0, sp
+ mov r1, #BAD_DATA
+ b SYMBOL_NAME(bad_mode)
+
+Ldata_do: mov r3, sp
+ ldr r4, [r0] @ Get instruction
+ tst r4, #1 << 20 @ Check to see if it is a write instruction
+ orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
+ mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
+ and r1, r1, #15 << 2
+ add pc, pc, r1
+ movs pc, lr
+ b Ldata_unknown
+ b Ldata_unknown
+ b Ldata_unknown
+ b Ldata_unknown
+ b Ldata_ldrstr_post @ ldr rd, [rn], #m
+ b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
+ b Ldata_ldrstr_post @ ldr rd, [rn], rm
+ b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
+ b Ldata_ldmstm @ ldm*a rn, <rlist>
+ b Ldata_ldmstm @ ldm*b rn, <rlist>
+ b Ldata_unknown
+ b Ldata_unknown
+ b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
+ b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
+ b Ldata_unknown
+Ldata_unknown: @ Part of jumptable
+ ldr r3, [sp, #15 * 4]
+ str r3, [sp, #-4]!
+ mov r1, r1, lsr #2
+ mov r2, r0
+ mov r3, r4
+ adr r0, Ltt
+ bl SYMBOL_NAME(printk)
+Llpxx: b Llpxx
+
+Ltt: .ascii "Unknown data abort code %d [pc=%p, *pc=%p]\nLR=%p\0"
+ .align
+
+Ldata_ldrstr_post:
+ mov r0, r4, lsr #14 @ Get Rn
+ and r0, r0, #15 << 2 @ Mask out reg.
+ teq r0, #15 << 2
+ ldr r0, [r3, r0] @ Get register
+ biceq r0, r0, #PCMASK
+ mov r1, r0
+#ifdef FAULT_CODE_LDRSTRPOST
+ orr r2, r2, #FAULT_CODE_LDRSTRPOST
+#endif
+ b SYMBOL_NAME(do_DataAbort)
+
+Ldata_ldrstr_numindex:
+ mov r0, r4, lsr #14 @ Get Rn
+ and r0, r0, #15 << 2 @ Mask out reg.
+ teq r0, #15 << 2
+ ldr r0, [r3, r0] @ Get register
+ biceq r0, r0, #PCMASK
+ mov r1, r4, lsl #20
+ tst r4, #1 << 23
+ addne r0, r0, r1, lsr #20
+ subeq r0, r0, r1, lsr #20
+ mov r1, r0
+#ifdef FAULT_CODE_LDRSTRPRE
+ orr r2, r2, #FAULT_CODE_LDRSTRPRE
+#endif
+ b SYMBOL_NAME(do_DataAbort)
+
+Ldata_ldrstr_regindex:
+ mov r0, r4, lsr #14 @ Get Rn
+ and r0, r0, #15 << 2 @ Mask out reg.
+ teq r0, #15 << 2
+ ldr r0, [r3, r0] @ Get register
+ biceq r0, r0, #PCMASK
+ and r7, r4, #15
+ teq r7, #15 @ Check for PC
+ ldr r7, [r3, r7, lsl #2] @ Get Rm
+ biceq r7, r7, #PCMASK
+ and r8, r4, #0x60 @ Get shift types
+ mov r9, r4, lsr #7 @ Get shift amount
+ and r9, r9, #31
+ teq r8, #0
+ moveq r7, r7, lsl r9
+ teq r8, #0x20 @ LSR shift
+ moveq r7, r7, lsr r9
+ teq r8, #0x40 @ ASR shift
+ moveq r7, r7, asr r9
+ teq r8, #0x60 @ ROR shift
+ moveq r7, r7, ror r9
+ tst r4, #1 << 23
+ addne r0, r0, r7
+ subeq r0, r0, r7 @ Apply correction
+ mov r1, r0
+#ifdef FAULT_CODE_LDRSTRREG
+ orr r2, r2, #FAULT_CODE_LDRSTRREG
+#endif
+ b SYMBOL_NAME(do_DataAbort)
+
+Ldata_ldmstm:
+ mov r7, #0x11
+ orr r7, r7, r7, lsl #8
+ and r0, r4, r7
+ and r1, r4, r7, lsl #1
+ add r0, r0, r1, lsr #1
+ and r1, r4, r7, lsl #2
+ add r0, r0, r1, lsr #2
+ and r1, r4, r7, lsl #3
+ add r0, r0, r1, lsr #3
+ add r0, r0, r0, lsr #8
+ add r0, r0, r0, lsr #4
+ and r7, r0, #15 @ r7 = no. of registers to transfer.
+ mov r5, r4, lsr #14 @ Get Rn
+ and r5, r5, #15 << 2
+ ldr r0, [r3, r5] @ Get reg
+ eor r6, r4, r4, lsl #2
+ tst r6, #1 << 23 @ Check inc/dec ^ writeback
+ rsbeq r7, r7, #0
+ add r7, r0, r7, lsl #2 @ Do correction (signed)
+ subne r1, r7, #1
+ subeq r1, r0, #1
+ moveq r0, r7
+ tst r4, #1 << 21 @ Check writeback
+ strne r7, [r3, r5]
+ eor r6, r4, r4, lsl #1
+ tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
+ addeq r0, r0, #4
+ addeq r1, r1, #4
+ teq r5, #15*4 @ CHECK FOR PC
+ biceq r1, r1, #PCMASK
+ biceq r0, r0, #PCMASK
+#ifdef FAULT_CODE_LDMSTM
+ orr r2, r2, #FAULT_CODE_LDMSTM
+#endif
+ b SYMBOL_NAME(do_DataAbort)
+
+Ldata_ldcstc_pre:
+ mov r0, r4, lsr #14 @ Get Rn
+ and r0, r0, #15 << 2 @ Mask out reg.
+ teq r0, #15 << 2
+ ldr r0, [r3, r0] @ Get register
+ biceq r0, r0, #PCMASK
+ mov r1, r4, lsl #24 @ Get offset
+ tst r4, #1 << 23
+ addne r0, r0, r1, lsr #24
+ subeq r0, r0, r1, lsr #24
+ mov r1, r0
+#ifdef FAULT_CODE_LDCSTC
+ orr r2, r2, #FAULT_CODE_LDCSTC
+#endif
+ b SYMBOL_NAME(do_DataAbort)
+
+#include "entry-common.S"
+
+ .data
+
+__temp_irq: .word 0 @ saved lr_irq
+__temp_fiq: .space 128
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov