/*
* arm exception handlers
*/
#include "arm.s"
#undef B /* B is for 'botch' */
/*
* 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 /* hypervisor call */
MOVW 0x18(R15), R15 /* IRQ */
MOVW 0x18(R15), R15 /* FIQ */
TEXT vtable(SB), 1, $-4
WORD $_vrst-KZERO(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 $_vhype(SB) /* hypervisor call */
WORD $_virq(SB) /* IRQ, switch to svc mode */
WORD $_vfiq(SB) /* FIQ, switch to svc mode */
/*
* reset - start additional cpus
*/
TEXT _vrst(SB), 1, $-4
/* running in the zero segment (pc is lower 256MB) */
CPSMODE(PsrMsvc) /* should be redundant */
CPSID
CPSAE
SETEND(0) /* force little-endian */
BARRIERS
SETZSB
MOVW $PsrMsvc, SPSR
MOVW $0, R14
/* invalidate i-cache and branch-target cache */
MTCP CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
BARRIERS
BL cpureset(SB)
spin:
B spin
/*
* system call
*/
TEXT _vsvc(SB), 1, $-4 /* SWI */
CLREX
BARRIERS
/* stack is m->stack */
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 $(NREGS*4), R13 /* r13 now points to ureg */
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
/*
* set up m and up registers since user registers could contain anything
*/
CPUID(R1)
SLL $2, R1 /* convert to word index */
MOVW $machaddr(SB), R2
ADD R1, R2
MOVW (R2), R(MACH) /* m = machaddr[cpuid] */
CMP $0, R(MACH)
MOVW.EQ $MACHADDR, R0 /* paranoia: use MACHADDR if 0 */
MOVW 8(R(MACH)), R(USER) /* up = m->proc */
MOVW ((NREGS+1)*4)(R13), R2 /* saved SPSR (user mode) */
MOVW R13, R0 /* first arg is pointer to ureg */
SUB $8, R13 /* space for argument+link */
BL syscall(SB)
/*
* caller saves on plan 9, so registers other than 9, 10, 13 & 14
* may have been trashed when we get here.
*/
MOVW $setR12(SB), R12 /* reload kernel's SB */
ADD $(8+4*NREGS), R13 /* make r13 point to ureg->type */
MOVW 8(R13), R14 /* restore link */
MOVW 4(R13), R0 /* restore SPSR */
/*
* return from user-mode exception.
* expects new SPSR in R0. R13 must point to ureg->type.
*/
_rfue:
TEXT rfue(SB), 1, $-4
MOVW R0, SPSR /* ... */
/*
* order on stack is type, psr, pc, but RFEV7 needs pc, psr.
* step on type and previous word to hold temporary values.
* we could instead change the order in which psr & pc are pushed.
*/
MOVW 4(R13), R1 /* psr */
MOVW 8(R13), R2 /* pc */
MOVW R2, 4(R13) /* pc */
MOVW R1, 8(R13) /* psr */
MOVM.DB.S (R13), [R0-R14] /* restore user registers */
ADD $4, R13 /* pop type, sp -> pc */
RFEV7W(13)
TEXT _vund(SB), 1, $-4 /* undefined */
/* sp is m->sund */
MOVM.IA [R0-R4], (R13) /* free some working space */
MOVW $PsrMund, R0
B _vswitch
TEXT _vpabt(SB), 1, $-4 /* prefetch abort */
/* sp is m->sabt */
MOVM.IA [R0-R4], (R13) /* free some working space */
MOVW $PsrMabt, R0 /* r0 = type */
B _vswitch
TEXT _vdabt(SB), 1, $-4 /* data abort */
/* sp is m->sabt */
MOVM.IA [R0-R4], (R13) /* free some working space */
MOVW $(PsrMabt+1), R0 /* r0 = type */
B _vswitch
TEXT _virq(SB), 1, $-4 /* IRQ */
/* sp is m->sirq */
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:
// TEXT _vswtch(SB), 1, $-4 /* make symbol visible to debuggers */
CLREX
BARRIERS
MOVW SPSR, R1 /* save SPSR for ureg */
/*
* R12 needs to be set before using PsrMbz, so BIGENDCHECK code has
* been moved below.
*/
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 (so we must be sure
* to never get here already in svc mode).
*/
CPSMODE(PsrMsvc) /* switch! */
CPSID
AND.S $0xf, R1, R4 /* interrupted code kernel or user? */
BEQ _userexcep
/*
* here for trap from SVC mode
*/
/* push ureg->{type, psr, pc} onto Msvc stack.
* r13 points to ureg->type after.
*/
MOVM.DB.W [R0-R2], (R13)
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 $(NREGS*4), R13 /* SP now points to saved R0 */
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
/* previous mode was svc, so the saved spsr should be sane. */
MOVW ((NREGS+1)*4)(R13), R1
MOVM.IA (R13), [R0-R8] /* restore a few user registers */
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) /* trap(ureg) */
/*
* caller saves on plan 9, so registers other than 9, 10, 13 & 14
* may have been trashed when we get here.
*/
MOVW $setR12(SB), R12 /* reload kernel's SB */
ADD $(4*2+4*NREGS), R13 /* make r13 point to ureg->type */
/*
* if we interrupted a previous trap's handler and are now
* returning to it, we need to propagate the current R(MACH) (R10)
* by overriding the saved one on the stack, since we may have
* been rescheduled and be on a different processor now than
* at entry.
*/
MOVW R(MACH), (-(NREGS-MACH)*4)(R13) /* restore current cpu's MACH */
MOVW 8(R13), R14 /* restore link */
MOVW 4(R13), R0 /* restore SPSR */
/* return from kernel-mode exception */
MOVW R0, SPSR /* ... */
/*
* order on stack is type, psr, pc, but RFEV7 needs pc, psr.
* step on type and previous word to hold temporary values.
* we could instead change the order in which psr & pc are pushed.
*/
MOVW 4(R13), R1 /* psr */
MOVW 8(R13), R2 /* pc */
MOVW R2, 4(R13) /* pc */
MOVW R1, 8(R13) /* psr */
/* restore kernel regs other than SP; we're using it */
SUB $(NREGS*4), R13
MOVM.IA.W (R13), [R0-R12]
ADD $4, R13 /* skip saved kernel SP */
MOVM.IA.W (R13), [R14]
ADD $4, R13 /* pop type, sp -> pc */
BARRIERS
RFEV7W(13)
/*
* 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 $(NREGS*4), R13 /* r13 now points to ureg */
MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
/*
* set up m and up registers since user registers could contain anything
*/
CPUID(R1)
SLL $2, R1 /* convert to word index */
MOVW $machaddr(SB), R2
ADD R1, R2
MOVW (R2), R(MACH) /* m = machaddr[cpuid] */
CMP $0, R(MACH)
MOVW.EQ $MACHADDR, R0 /* paranoia: use MACHADDR if 0 */
MOVW 8(R(MACH)), R(USER) /* up = m->proc */
MOVW ((NREGS+1)*4)(R13), R2 /* saved SPSR */
MOVW R13, R0 /* first arg is pointer to ureg */
SUB $(4*2), R13 /* space for argument+link (for debugger) */
BL trap(SB) /* trap(ureg) */
/*
* caller saves on plan 9, so registers other than 9, 10, 13 & 14
* may have been trashed when we get here.
*/
ADD $(4*2+4*NREGS), R13 /* make r13 point to ureg->type */
MOVW 8(R13), R14 /* restore link */
MOVW 4(R13), R0 /* restore SPSR */
MOVW 4(R13), R0 /* restore SPSR */
B _rfue
TEXT _vfiq(SB), 1, $-4 /* FIQ */
PUTC('?')
PUTC('f')
PUTC('i')
PUTC('q')
RFE /* FIQ is special, ignore it for now */
TEXT _vhype(SB), 1, $-4
PUTC('?')
PUTC('h')
PUTC('y')
PUTC('p')
RFE
/*
* set the stack value for the mode passed in R0
*/
TEXT setr13(SB), 1, $-4
MOVW 4(FP), R1
MOVW CPSR, R2
BIC $(PsrMask|PsrMbz), R2, R3
ORR $(PsrDirq|PsrDfiq), 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
|