* Assembled from chunks of code in arch/arm
*
* Copyright (C) 2003 Ian Molton
+ * Based on the work of RMK.
*
*/
-#include <linux/config.h> /* for CONFIG_ARCH_xxxx */
#include <linux/linkage.h>
#include <asm/assembler.h>
#define BAD_IRQ 3
#define BAD_UNDEFINSTR 4
-#define PT_TRACESYS 0x00000002
-
@ OS version number used in SWIs
@ RISC OS is 0
@ RISC iX is 8
@
@ Stack format (ensured by USER_* and SVC_*)
+@ PSR and PC are comined on arm26
@
-#define S_FRAME_SIZE 72 @ FIXME: Really?
+
+#define S_OFF 8
+
#define S_OLD_R0 64
-#define S_PSR 60
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_R2 8
#define S_R1 4
#define S_R0 0
-#define S_OFF 8
.macro save_user_regs
- str r0, [sp, #-4]!
- str lr, [sp, #-4]!
+ str r0, [sp, #-4]! @ Store SVC r0
+ str lr, [sp, #-4]! @ Store user mode PC
sub sp, sp, #15*4
- stmia sp, {r0 - lr}^
+ stmia sp, {r0 - lr}^ @ Store the other user-mode regs
mov r0, r0
.endm
.macro slow_restore_user_regs
- ldmia sp, {r0 - lr}^ @ restore the user regs
- mov r0, r0 @ no-op
+ ldmia sp, {r0 - lr}^ @ restore the user regs not including PC
+ mov r0, r0
ldr lr, [sp, #15*4] @ get user PC
add sp, sp, #15*4+8 @ free stack
movs pc, lr @ return
movs pc, lr
.endm
+ .macro save_svc_regs
+ 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]
+ zero_fp
+ .endm
+
+ .macro save_svc_regs_irq
+ 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]
+ zero_fp
+ .endm
+
+ .macro restore_svc_regs
+ ldmfd sp, {r0 - pc}^
+ .endm
+
.macro mask_pc, rd, rm
bic \rd, \rm, #PCMASK
.endm
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, #PSR_I_BIT | MODE_SVC26
- .endm
-
-
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6.
*
- * r7 is reserved for the system call number for thumb mode.
- *
* Note that tbl == why is intentional.
*
* We must set at least "tsk" and "why" when calling ret_with_reschedule.
#error "Please fix"
#endif
-/*
- * Our do_softirq out of line code. See include/asm-arm26/hardirq.h for
- * the calling assembly.
- */
-ENTRY(__do_softirq)
- stmfd sp!, {r0 - r3, ip, lr}
- bl do_softirq
- ldmfd sp!, {r0 - r3, ip, pc}
-
- .align 5
-
/*
* This is the fast syscall return path. We do as little as
* possible here, and this includes saving r0 back into the SVC
bl syscall_trace
b ret_slow_syscall
-#include <asm/calls.h>
+// FIXME - is this strictly necessary?
+#include "calls.S"
/*=============================================================================
* SWI handler
tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
bne __sys_trace
- adrsvc al, lr, ret_fast_syscall @ return address
+ adral lr, ret_fast_syscall @ set return address
+ orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
cmp scno, #NR_syscalls @ check upper syscall limit
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
mov r0, #0 @ trace entry [IP = 0]
bl syscall_trace
- adrsvc al, lr, __sys_trace_return @ return address
+ adral lr, __sys_trace_return @ set return address
+ orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
add r1, sp, #S_R0 + S_OFF @ pointer to regs
cmp scno, #NR_syscalls @ check upper syscall limit
ldmccia r1, {r0 - r3} @ have to reload r0 - r3
.type sys_call_table, #object
ENTRY(sys_call_table)
-#include <asm/calls.h>
+#include "calls.S"
/*============================================================================
* Special system call wrappers
.text
- .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
+ .macro handle_irq
+1: mov r4, #IOC_BASE
+ ldrb r6, [r4, #0x24] @ get high priority first
+ adr r5, irq_prio_h
+ teq r6, #0
+ ldreqb r6, [r4, #0x14] @ get low priority
+ adreq r5, irq_prio_l
+
+ teq r6, #0 @ If an IRQ happened...
+ ldrneb r0, [r5, r6] @ get IRQ number
+ movne r1, sp @ get struct pt_regs
+ adrne lr, 1b @ Set return address to 1b
+ orrne lr, lr, #PSR_I_BIT | MODE_SVC26 @ (and force SVC mode)
+ bne asm_do_IRQ @ process IRQ (if asserted)
.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)
.endm
#if 1
-/* FIXME (well, ok, dont - but its easy to grep for :) */
/*
* Uncomment these if you wish to get more debugging into about data aborts.
+ * FIXME - I bet we can find a way to encode these and keep performance.
*/
#define FAULT_CODE_LDRSTRPOST 0x80
#define FAULT_CODE_LDRSTRPRE 0x40
#define FAULT_CODE_WRITE 0x02
#define FAULT_CODE_FORCECOW 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] ;\
- zero_fp
-
-#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] ;\
- zero_fp
-
-#define SVC_RESTORE_ALL \
- ldmfd sp, {r0 - pc}^
-
/*=============================================================================
* Undefined FIQs
*-----------------------------------------------------------------------------
/* FIXME - should we trap for a null pointer here? */
/* The SVC mode case */
-__und_svc: SVC_SAVE_ALL @ Non-user mode
+__und_svc: save_svc_regs @ Non-user mode
mask_pc r0, lr
and r2, lr, #3
sub r0, r0, #4
mov r1, sp
bl do_undefinstr
- SVC_RESTORE_ALL
+ restore_svc_regs
/* We get here if the FP emulator doesnt handle the undef instr.
* If the insn WAS handled, the emulator jumps to ret_from_exception by itself/
ldr lr, [sp,#S_PC] @ FIXME program to test this on. I think its
b .Lbug_undef @ broken at the moment though!)
-__pabt_invalid: SVC_SAVE_ALL
+__pabt_invalid: save_svc_regs
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 ret_from_exception
Laddrexcptn_not_user:
- SVC_SAVE_ALL
+ save_svc_regs
and r2, lr, #3
teq r2, #3
bne Laddrexcptn_illegal_mode
/*=============================================================================
* Interrupt (IRQ) handler
*-----------------------------------------------------------------------------
- * Note: if in user mode, then *no* kernel routine is running, so do not have
- * to save svc lr
- * (r13 points to irq temp save area)
+ * Note: if the IRQ was taken whilst in user mode, then *no* kernel routine
+ * is running, so do not have to save svc lr.
+ *
+ * Entered in IRQ mode.
*/
-vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case...
- sub lr, lr, #4
- str lr, [r13]
- tst lr, #3
- bne __irq_svc
- teqp pc, #PSR_I_BIT | MODE_SVC26
+vector_IRQ: ldr sp, .LCirq @ Setup some temporary stack
+ sub lr, lr, #4
+ str lr, [sp] @ push return address
+
+ tst lr, #3
+ bne __irq_non_usr
+
+__irq_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
mov r0, r0
+
ldr lr, .LCirq
- ldr lr, [lr]
+ ldr lr, [lr] @ Restore lr for jump back to USR
+
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, #PSR_I_BIT | MODE_SVC26 @ Force SVC
- bne asm_do_IRQ
+ handle_irq
mov why, #0
- get_thread_info tsk @ FIXME - was r5, but seemed wrong.
+ get_thread_info tsk
b ret_to_user
+@ Place the IRQ priority table here so that the handle_irq macros above
+@ and below here can access it.
+
irq_prio_table
-__irq_svc: teqp pc, #PSR_I_BIT | MODE_SVC26
+__irq_non_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
mov r0, r0
- SVC_IRQ_SAVE_ALL
+
+ save_svc_regs_irq
+
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, #PSR_I_BIT | MODE_SVC26 @ Force SVC
- bne asm_do_IRQ @ Returns to 1b
- SVC_RESTORE_ALL
+ bne __irq_invalid @ IRQ not from SVC mode
+
+ handle_irq
+
+ restore_svc_regs
__irq_invalid: mov r0, sp
mov r1, #BAD_IRQ
b ret_from_exception
Ldata_not_user:
- SVC_SAVE_ALL
+ save_svc_regs
and r2, lr, #3
teq r2, #3
bne Ldata_illegal_mode
teqeqp pc, #MODE_SVC26
mask_pc r0, lr
bl Ldata_do
- SVC_RESTORE_ALL
+ restore_svc_regs
Ldata_illegal_mode:
mov r0, sp