1*5d9de2d3SDavid du Colombier/* 2*5d9de2d3SDavid du Colombier * arm exception handlers 3*5d9de2d3SDavid du Colombier */ 4*5d9de2d3SDavid du Colombier#include "arm.s" 5*5d9de2d3SDavid du Colombier 6*5d9de2d3SDavid du Colombier/* 7*5d9de2d3SDavid du Colombier * exception vectors, copied by trapinit() to somewhere useful 8*5d9de2d3SDavid du Colombier */ 9*5d9de2d3SDavid du ColombierTEXT vectors(SB), 1, $-4 10*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* reset */ 11*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* undefined instr. */ 12*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* SWI & SMC */ 13*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* prefetch abort */ 14*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* data abort */ 15*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* reserved */ 16*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* IRQ */ 17*5d9de2d3SDavid du Colombier MOVW 0x18(R15), R15 /* FIQ */ 18*5d9de2d3SDavid du Colombier 19*5d9de2d3SDavid du ColombierTEXT vtable(SB), 1, $-4 20*5d9de2d3SDavid du Colombier WORD $_vsvc(SB) /* reset, in svc mode already */ 21*5d9de2d3SDavid du Colombier WORD $_vund(SB) /* undefined, switch to svc mode */ 22*5d9de2d3SDavid du Colombier WORD $_vsvc(SB) /* swi, in svc mode already */ 23*5d9de2d3SDavid du Colombier WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */ 24*5d9de2d3SDavid du Colombier WORD $_vdabt(SB) /* data abort, switch to svc mode */ 25*5d9de2d3SDavid du Colombier WORD $_vsvc(SB) /* reserved */ 26*5d9de2d3SDavid du Colombier WORD $_virq(SB) /* IRQ, switch to svc mode */ 27*5d9de2d3SDavid du Colombier WORD $_vfiq(SB) /* FIQ, switch to svc mode */ 28*5d9de2d3SDavid du Colombier 29*5d9de2d3SDavid du ColombierTEXT _vsvc(SB), 1, $-4 /* SWI */ 30*5d9de2d3SDavid du Colombier MOVW.W R14, -4(R13) /* ureg->pc = interrupted PC */ 31*5d9de2d3SDavid du Colombier MOVW SPSR, R14 /* ureg->psr = SPSR */ 32*5d9de2d3SDavid du Colombier MOVW.W R14, -4(R13) /* ... */ 33*5d9de2d3SDavid du Colombier MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */ 34*5d9de2d3SDavid du Colombier MOVW.W R14, -4(R13) /* ... */ 35*5d9de2d3SDavid du Colombier 36*5d9de2d3SDavid du Colombier /* avoid the ambiguity described in notes/movm.w. */ 37*5d9de2d3SDavid du Colombier MOVM.DB.S [R0-R14], (R13) /* save user level registers */ 38*5d9de2d3SDavid du Colombier SUB $(15*4), R13 /* r13 now points to ureg */ 39*5d9de2d3SDavid du Colombier 40*5d9de2d3SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 41*5d9de2d3SDavid du Colombier 42*5d9de2d3SDavid du Colombier// MOVW $(KSEG0+16*KiB-MACHSIZE), R10 /* m */ 43*5d9de2d3SDavid du Colombier MOVW $(MACHADDR), R10 /* m */ 44*5d9de2d3SDavid du Colombier MOVW 8(R10), R9 /* up */ 45*5d9de2d3SDavid du Colombier 46*5d9de2d3SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 47*5d9de2d3SDavid du Colombier SUB $8, R13 /* space for argument+link */ 48*5d9de2d3SDavid du Colombier 49*5d9de2d3SDavid du Colombier BL syscall(SB) 50*5d9de2d3SDavid du Colombier 51*5d9de2d3SDavid du Colombier ADD $(8+4*15), R13 /* make r13 point to ureg->type */ 52*5d9de2d3SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 53*5d9de2d3SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 54*5d9de2d3SDavid du Colombier MOVW R0, SPSR /* ... */ 55*5d9de2d3SDavid du Colombier MOVM.DB.S (R13), [R0-R14] /* restore registers */ 56*5d9de2d3SDavid du Colombier ADD $8, R13 /* pop past ureg->{type+psr} */ 57*5d9de2d3SDavid du Colombier RFE /* MOVM.IA.S.W (R13), [R15] */ 58*5d9de2d3SDavid du Colombier 59*5d9de2d3SDavid du ColombierTEXT _vund(SB), 1, $-4 /* undefined */ 60*5d9de2d3SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 61*5d9de2d3SDavid du Colombier MOVW $PsrMund, R0 62*5d9de2d3SDavid du Colombier B _vswitch 63*5d9de2d3SDavid du Colombier 64*5d9de2d3SDavid du ColombierTEXT _vpabt(SB), 1, $-4 /* prefetch abort */ 65*5d9de2d3SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 66*5d9de2d3SDavid du Colombier MOVW $PsrMabt, R0 /* r0 = type */ 67*5d9de2d3SDavid du Colombier B _vswitch 68*5d9de2d3SDavid du Colombier 69*5d9de2d3SDavid du ColombierTEXT _vdabt(SB), 1, $-4 /* data abort */ 70*5d9de2d3SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 71*5d9de2d3SDavid du Colombier MOVW $(PsrMabt+1), R0 /* r0 = type */ 72*5d9de2d3SDavid du Colombier B _vswitch 73*5d9de2d3SDavid du Colombier 74*5d9de2d3SDavid du ColombierTEXT _virq(SB), 1, $-4 /* IRQ */ 75*5d9de2d3SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 76*5d9de2d3SDavid du Colombier MOVW $PsrMirq, R0 /* r0 = type */ 77*5d9de2d3SDavid du Colombier B _vswitch 78*5d9de2d3SDavid du Colombier 79*5d9de2d3SDavid du Colombier /* 80*5d9de2d3SDavid du Colombier * come here with type in R0 and R13 pointing above saved [r0-r4]. 81*5d9de2d3SDavid du Colombier * we'll switch to SVC mode and then call trap. 82*5d9de2d3SDavid du Colombier */ 83*5d9de2d3SDavid du Colombier_vswitch: 84*5d9de2d3SDavid du Colombier MOVW SPSR, R1 /* save SPSR for ureg */ 85*5d9de2d3SDavid du Colombier MOVW R14, R2 /* save interrupted pc for ureg */ 86*5d9de2d3SDavid du Colombier MOVW R13, R3 /* save pointer to where the original [R0-R4] are */ 87*5d9de2d3SDavid du Colombier 88*5d9de2d3SDavid du Colombier /* 89*5d9de2d3SDavid du Colombier * switch processor to svc mode. this switches the banked registers 90*5d9de2d3SDavid du Colombier * (r13 [sp] and r14 [link]) to those of svc mode. 91*5d9de2d3SDavid du Colombier */ 92*5d9de2d3SDavid du Colombier MOVW CPSR, R14 93*5d9de2d3SDavid du Colombier BIC $PsrMask, R14 94*5d9de2d3SDavid du Colombier ORR $(PsrDirq|PsrMsvc), R14 95*5d9de2d3SDavid du Colombier MOVW R14, CPSR /* switch! */ 96*5d9de2d3SDavid du Colombier 97*5d9de2d3SDavid du Colombier AND.S $0xf, R1, R4 /* interrupted code kernel or user? */ 98*5d9de2d3SDavid du Colombier BEQ _userexcep 99*5d9de2d3SDavid du Colombier 100*5d9de2d3SDavid du Colombier /* here for trap from SVC mode */ 101*5d9de2d3SDavid du Colombier MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ 102*5d9de2d3SDavid du Colombier MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ 103*5d9de2d3SDavid du Colombier 104*5d9de2d3SDavid du Colombier /* 105*5d9de2d3SDavid du Colombier * avoid the ambiguity described in notes/movm.w. 106*5d9de2d3SDavid du Colombier * In order to get a predictable value in R13 after the stores, 107*5d9de2d3SDavid du Colombier * separate the store-multiple from the stack-pointer adjustment. 108*5d9de2d3SDavid du Colombier * We'll assume that the old value of R13 should be stored on the stack. 109*5d9de2d3SDavid du Colombier */ 110*5d9de2d3SDavid du Colombier /* save kernel level registers, at end r13 points to ureg */ 111*5d9de2d3SDavid du Colombier MOVM.DB [R0-R14], (R13) 112*5d9de2d3SDavid du Colombier SUB $(15*4), R13 /* SP now points to saved R0 */ 113*5d9de2d3SDavid du Colombier 114*5d9de2d3SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 115*5d9de2d3SDavid du Colombier 116*5d9de2d3SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 117*5d9de2d3SDavid du Colombier SUB $(4*2), R13 /* space for argument+link (for debugger) */ 118*5d9de2d3SDavid du Colombier MOVW $0xdeaddead, R11 /* marker */ 119*5d9de2d3SDavid du Colombier 120*5d9de2d3SDavid du Colombier BL trap(SB) 121*5d9de2d3SDavid du Colombier 122*5d9de2d3SDavid du Colombier ADD $(4*2+4*15), R13 /* make r13 point to ureg->type */ 123*5d9de2d3SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 124*5d9de2d3SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 125*5d9de2d3SDavid du Colombier MOVW R0, SPSR /* ... */ 126*5d9de2d3SDavid du Colombier 127*5d9de2d3SDavid du Colombier MOVM.DB (R13), [R0-R14] /* restore registers */ 128*5d9de2d3SDavid du Colombier 129*5d9de2d3SDavid du Colombier ADD $(4*2), R13 /* pop past ureg->{type+psr} to pc */ 130*5d9de2d3SDavid du Colombier RFE /* MOVM.IA.S.W (R13), [R15] */ 131*5d9de2d3SDavid du Colombier 132*5d9de2d3SDavid du Colombier /* here for trap from USER mode */ 133*5d9de2d3SDavid du Colombier_userexcep: 134*5d9de2d3SDavid du Colombier MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ 135*5d9de2d3SDavid du Colombier MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ 136*5d9de2d3SDavid du Colombier 137*5d9de2d3SDavid du Colombier /* avoid the ambiguity described in notes/movm.w. */ 138*5d9de2d3SDavid du Colombier MOVM.DB.S [R0-R14], (R13) /* save kernel level registers */ 139*5d9de2d3SDavid du Colombier SUB $(15*4), R13 /* r13 now points to ureg */ 140*5d9de2d3SDavid du Colombier 141*5d9de2d3SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 142*5d9de2d3SDavid du Colombier 143*5d9de2d3SDavid du Colombier// MOVW $(KSEG0+16*KiB-MACHSIZE), R10 /* m */ 144*5d9de2d3SDavid du Colombier MOVW $(MACHADDR), R10 /* m */ 145*5d9de2d3SDavid du Colombier MOVW 8(R10), R9 /* up */ 146*5d9de2d3SDavid du Colombier 147*5d9de2d3SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 148*5d9de2d3SDavid du Colombier SUB $(4*2), R13 /* space for argument+link (for debugger) */ 149*5d9de2d3SDavid du Colombier 150*5d9de2d3SDavid du Colombier BL trap(SB) 151*5d9de2d3SDavid du Colombier 152*5d9de2d3SDavid du Colombier ADD $(4*2+4*15), R13 /* make r13 point to ureg->type */ 153*5d9de2d3SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 154*5d9de2d3SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 155*5d9de2d3SDavid du Colombier MOVW R0, SPSR /* ... */ 156*5d9de2d3SDavid du Colombier MOVM.DB.S (R13), [R0-R14] /* restore registers */ 157*5d9de2d3SDavid du Colombier ADD $(4*2), R13 /* pop past ureg->{type+psr} */ 158*5d9de2d3SDavid du Colombier RFE /* MOVM.IA.S.W (R13), [R15] */ 159*5d9de2d3SDavid du Colombier 160*5d9de2d3SDavid du ColombierTEXT _vfiq(SB), 1, $-4 /* FIQ */ 161*5d9de2d3SDavid du Colombier MOVW $PsrMfiq, R8 /* trap type */ 162*5d9de2d3SDavid du Colombier MOVW SPSR, R9 /* interrupted psr */ 163*5d9de2d3SDavid du Colombier MOVW R14, R10 /* interrupted pc */ 164*5d9de2d3SDavid du Colombier MOVM.DB.W [R8-R10], (R13) /* save in ureg */ 165*5d9de2d3SDavid du Colombier MOVM.DB.W.S [R0-R14], (R13) /* save interrupted regs */ 166*5d9de2d3SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 167*5d9de2d3SDavid du Colombier MOVW $(MACHADDR), R10 /* m */ 168*5d9de2d3SDavid du Colombier MOVW 8(R10), R9 /* up */ 169*5d9de2d3SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 170*5d9de2d3SDavid du Colombier SUB $(4*2), R13 /* space for argument+link (for debugger) */ 171*5d9de2d3SDavid du Colombier 172*5d9de2d3SDavid du Colombier BL fiq(SB) 173*5d9de2d3SDavid du Colombier 174*5d9de2d3SDavid du Colombier ADD $(8+4*15), R13 /* make r13 point to ureg->type */ 175*5d9de2d3SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 176*5d9de2d3SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 177*5d9de2d3SDavid du Colombier MOVW R0, SPSR /* ... */ 178*5d9de2d3SDavid du Colombier MOVM.DB.S (R13), [R0-R14] /* restore registers */ 179*5d9de2d3SDavid du Colombier ADD $8, R13 /* pop past ureg->{type+psr} */ 180*5d9de2d3SDavid du Colombier RFE /* MOVM.IA.S.W (R13), [R15] */ 181*5d9de2d3SDavid du Colombier 182*5d9de2d3SDavid du Colombier/* 183*5d9de2d3SDavid du Colombier * set the stack value for the mode passed in R0 184*5d9de2d3SDavid du Colombier */ 185*5d9de2d3SDavid du ColombierTEXT setr13(SB), 1, $-4 186*5d9de2d3SDavid du Colombier MOVW 4(FP), R1 187*5d9de2d3SDavid du Colombier 188*5d9de2d3SDavid du Colombier MOVW CPSR, R2 189*5d9de2d3SDavid du Colombier BIC $PsrMask, R2, R3 190*5d9de2d3SDavid du Colombier ORR R0, R3 191*5d9de2d3SDavid du Colombier MOVW R3, CPSR /* switch to new mode */ 192*5d9de2d3SDavid du Colombier 193*5d9de2d3SDavid du Colombier MOVW R13, R0 /* return old sp */ 194*5d9de2d3SDavid du Colombier MOVW R1, R13 /* install new one */ 195*5d9de2d3SDavid du Colombier 196*5d9de2d3SDavid du Colombier MOVW R2, CPSR /* switch back to old mode */ 197*5d9de2d3SDavid du Colombier RET 198