/* * arm exception handlers */ #include "arm.s" /* * exception vectors, copied by trapinit() to somewhere useful */ TEXT vectors(SB), 1, $-4 MOVW 0x18(R15), R15 /* reset */ MOVW 0x18(R15), R15 /* undefined instr. */ MOVW 0x18(R15), R15 /* SWI & SMC */ MOVW 0x18(R15), R15 /* prefetch abort */ MOVW 0x18(R15), R15 /* data abort */ MOVW 0x18(R15), R15 /* reserved */ MOVW 0x18(R15), R15 /* IRQ */ MOVW 0x18(R15), R15 /* FIQ */ TEXT vtable(SB), 1, $-4 WORD $_vsvc(SB) /* reset, in svc mode already */ WORD $_vund(SB) /* undefined, switch to svc mode */ WORD $_vsvc(SB) /* swi, in svc mode already */ WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */ WORD $_vdabt(SB) /* data abort, switch to svc mode */ WORD $_vsvc(SB) /* reserved */ WORD $_virq(SB) /* IRQ, switch to svc mode */ WORD $_vfiq(SB) /* FIQ, switch to svc mode */ TEXT _vsvc(SB), 1, $-4 /* SWI */ MOVW.W R14, -4(R13) /* ureg->pc = interrupted PC */ MOVW SPSR, R14 /* ureg->psr = SPSR */ MOVW.W R14, -4(R13) /* ... */ MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */ MOVW.W R14, -4(R13) /* ... */ /* avoid the ambiguity described in notes/movm.w. */ MOVM.DB.S [R0-R14], (R13) /* save user level registers */ SUB $(15*4), R13 /* r13 now points to ureg */ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ // MOVW $(KSEG0+16*KiB-MACHSIZE), R10 /* m */ MOVW $(MACHADDR), R10 /* m */ MOVW 8(R10), R9 /* up */ MOVW R13, R0 /* first arg is pointer to ureg */ SUB $8, R13 /* space for argument+link */ BL syscall(SB) ADD $(8+4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ MOVW 4(R13), R0 /* restore SPSR */ MOVW R0, SPSR /* ... */ MOVM.DB.S (R13), [R0-R14] /* restore registers */ ADD $8, R13 /* pop past ureg->{type+psr} */ RFE /* MOVM.IA.S.W (R13), [R15] */ TEXT _vund(SB), 1, $-4 /* undefined */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMund, R0 B _vswitch TEXT _vpabt(SB), 1, $-4 /* prefetch abort */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMabt, R0 /* r0 = type */ B _vswitch TEXT _vdabt(SB), 1, $-4 /* data abort */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $(PsrMabt+1), R0 /* r0 = type */ B _vswitch TEXT _virq(SB), 1, $-4 /* IRQ */ MOVM.IA [R0-R4], (R13) /* free some working space */ MOVW $PsrMirq, R0 /* r0 = type */ B _vswitch /* * come here with type in R0 and R13 pointing above saved [r0-r4]. * we'll switch to SVC mode and then call trap. */ _vswitch: MOVW SPSR, R1 /* save SPSR for ureg */ MOVW R14, R2 /* save interrupted pc for ureg */ MOVW R13, R3 /* save pointer to where the original [R0-R4] are */ /* * switch processor to svc mode. this switches the banked registers * (r13 [sp] and r14 [link]) to those of svc mode. */ MOVW CPSR, R14 BIC $PsrMask, R14 ORR $(PsrDirq|PsrMsvc), R14 MOVW R14, CPSR /* switch! */ AND.S $0xf, R1, R4 /* interrupted code kernel or user? */ BEQ _userexcep /* here for trap from SVC mode */ MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ /* * avoid the ambiguity described in notes/movm.w. * In order to get a predictable value in R13 after the stores, * separate the store-multiple from the stack-pointer adjustment. * We'll assume that the old value of R13 should be stored on the stack. */ /* save kernel level registers, at end r13 points to ureg */ MOVM.DB [R0-R14], (R13) SUB $(15*4), R13 /* SP now points to saved R0 */ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ MOVW R13, R0 /* first arg is pointer to ureg */ SUB $(4*2), R13 /* space for argument+link (for debugger) */ MOVW $0xdeaddead, R11 /* marker */ BL trap(SB) ADD $(4*2+4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ MOVW 4(R13), R0 /* restore SPSR */ MOVW R0, SPSR /* ... */ MOVM.DB (R13), [R0-R14] /* restore registers */ ADD $(4*2), R13 /* pop past ureg->{type+psr} to pc */ RFE /* MOVM.IA.S.W (R13), [R15] */ /* here for trap from USER mode */ _userexcep: MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ /* avoid the ambiguity described in notes/movm.w. */ MOVM.DB.S [R0-R14], (R13) /* save kernel level registers */ SUB $(15*4), R13 /* r13 now points to ureg */ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ // MOVW $(KSEG0+16*KiB-MACHSIZE), R10 /* m */ MOVW $(MACHADDR), R10 /* m */ MOVW 8(R10), R9 /* up */ MOVW R13, R0 /* first arg is pointer to ureg */ SUB $(4*2), R13 /* space for argument+link (for debugger) */ BL trap(SB) ADD $(4*2+4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ MOVW 4(R13), R0 /* restore SPSR */ MOVW R0, SPSR /* ... */ MOVM.DB.S (R13), [R0-R14] /* restore registers */ ADD $(4*2), R13 /* pop past ureg->{type+psr} */ RFE /* MOVM.IA.S.W (R13), [R15] */ TEXT _vfiq(SB), 1, $-4 /* FIQ */ MOVW $PsrMfiq, R8 /* trap type */ MOVW SPSR, R9 /* interrupted psr */ MOVW R14, R10 /* interrupted pc */ MOVM.DB.W [R8-R10], (R13) /* save in ureg */ MOVM.DB.W.S [R0-R14], (R13) /* save interrupted regs */ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ MOVW $(MACHADDR), R10 /* m */ MOVW 8(R10), R9 /* up */ MOVW R13, R0 /* first arg is pointer to ureg */ SUB $(4*2), R13 /* space for argument+link (for debugger) */ BL fiq(SB) ADD $(8+4*15), R13 /* make r13 point to ureg->type */ MOVW 8(R13), R14 /* restore link */ MOVW 4(R13), R0 /* restore SPSR */ MOVW R0, SPSR /* ... */ MOVM.DB.S (R13), [R0-R14] /* restore registers */ ADD $8, R13 /* pop past ureg->{type+psr} */ RFE /* MOVM.IA.S.W (R13), [R15] */ /* * set the stack value for the mode passed in R0 */ TEXT setr13(SB), 1, $-4 MOVW 4(FP), R1 MOVW CPSR, R2 BIC $PsrMask, R2, R3 ORR R0, R3 MOVW R3, CPSR /* switch to new mode */ MOVW R13, R0 /* return old sp */ MOVW R1, R13 /* install new one */ MOVW R2, CPSR /* switch back to old mode */ RET