1*3de6a9c0SDavid du Colombier/* 2*3de6a9c0SDavid du Colombier * arm exception handlers 3*3de6a9c0SDavid du Colombier */ 4*3de6a9c0SDavid du Colombier#include "arm.s" 5*3de6a9c0SDavid du Colombier 6*3de6a9c0SDavid du Colombier#undef B /* B is for 'botch' */ 7*3de6a9c0SDavid du Colombier 8*3de6a9c0SDavid du Colombier/* 9*3de6a9c0SDavid du Colombier * exception vectors, copied by trapinit() to somewhere useful 10*3de6a9c0SDavid du Colombier */ 11*3de6a9c0SDavid du ColombierTEXT vectors(SB), 1, $-4 12*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* reset */ 13*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* undefined instr. */ 14*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* SWI & SMC */ 15*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* prefetch abort */ 16*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* data abort */ 17*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* hypervisor call */ 18*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* IRQ */ 19*3de6a9c0SDavid du Colombier MOVW 0x18(R15), R15 /* FIQ */ 20*3de6a9c0SDavid du Colombier 21*3de6a9c0SDavid du ColombierTEXT vtable(SB), 1, $-4 22*3de6a9c0SDavid du Colombier WORD $_vrst-KZERO(SB) /* reset, in svc mode already */ 23*3de6a9c0SDavid du Colombier WORD $_vund(SB) /* undefined, switch to svc mode */ 24*3de6a9c0SDavid du Colombier WORD $_vsvc(SB) /* swi, in svc mode already */ 25*3de6a9c0SDavid du Colombier WORD $_vpabt(SB) /* prefetch abort, switch to svc mode */ 26*3de6a9c0SDavid du Colombier WORD $_vdabt(SB) /* data abort, switch to svc mode */ 27*3de6a9c0SDavid du Colombier WORD $_vhype(SB) /* hypervisor call */ 28*3de6a9c0SDavid du Colombier WORD $_virq(SB) /* IRQ, switch to svc mode */ 29*3de6a9c0SDavid du Colombier WORD $_vfiq(SB) /* FIQ, switch to svc mode */ 30*3de6a9c0SDavid du Colombier 31*3de6a9c0SDavid du Colombier/* 32*3de6a9c0SDavid du Colombier * reset - start additional cpus 33*3de6a9c0SDavid du Colombier */ 34*3de6a9c0SDavid du ColombierTEXT _vrst(SB), 1, $-4 35*3de6a9c0SDavid du Colombier /* running in the zero segment (pc is lower 256MB) */ 36*3de6a9c0SDavid du Colombier CPSMODE(PsrMsvc) /* should be redundant */ 37*3de6a9c0SDavid du Colombier CPSID 38*3de6a9c0SDavid du Colombier CPSAE 39*3de6a9c0SDavid du Colombier SETEND(0) /* force little-endian */ 40*3de6a9c0SDavid du Colombier BARRIERS 41*3de6a9c0SDavid du Colombier SETZSB 42*3de6a9c0SDavid du Colombier MOVW $PsrMsvc, SPSR 43*3de6a9c0SDavid du Colombier MOVW $0, R14 44*3de6a9c0SDavid du Colombier 45*3de6a9c0SDavid du Colombier /* invalidate i-cache and branch-target cache */ 46*3de6a9c0SDavid du Colombier MTCP CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall 47*3de6a9c0SDavid du Colombier BARRIERS 48*3de6a9c0SDavid du Colombier 49*3de6a9c0SDavid du Colombier BL cpureset(SB) 50*3de6a9c0SDavid du Colombierspin: 51*3de6a9c0SDavid du Colombier B spin 52*3de6a9c0SDavid du Colombier 53*3de6a9c0SDavid du Colombier/* 54*3de6a9c0SDavid du Colombier * system call 55*3de6a9c0SDavid du Colombier */ 56*3de6a9c0SDavid du ColombierTEXT _vsvc(SB), 1, $-4 /* SWI */ 57*3de6a9c0SDavid du Colombier CLREX 58*3de6a9c0SDavid du Colombier BARRIERS 59*3de6a9c0SDavid du Colombier /* stack is m->stack */ 60*3de6a9c0SDavid du Colombier MOVW.W R14, -4(R13) /* ureg->pc = interrupted PC */ 61*3de6a9c0SDavid du Colombier MOVW SPSR, R14 /* ureg->psr = SPSR */ 62*3de6a9c0SDavid du Colombier MOVW.W R14, -4(R13) /* ... */ 63*3de6a9c0SDavid du Colombier MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */ 64*3de6a9c0SDavid du Colombier MOVW.W R14, -4(R13) /* ... */ 65*3de6a9c0SDavid du Colombier 66*3de6a9c0SDavid du Colombier /* avoid the ambiguity described in notes/movm.w. */ 67*3de6a9c0SDavid du Colombier MOVM.DB.S [R0-R14], (R13) /* save user level registers */ 68*3de6a9c0SDavid du Colombier SUB $(NREGS*4), R13 /* r13 now points to ureg */ 69*3de6a9c0SDavid du Colombier 70*3de6a9c0SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 71*3de6a9c0SDavid du Colombier 72*3de6a9c0SDavid du Colombier /* 73*3de6a9c0SDavid du Colombier * set up m and up registers since user registers could contain anything 74*3de6a9c0SDavid du Colombier */ 75*3de6a9c0SDavid du Colombier CPUID(R1) 76*3de6a9c0SDavid du Colombier SLL $2, R1 /* convert to word index */ 77*3de6a9c0SDavid du Colombier MOVW $machaddr(SB), R2 78*3de6a9c0SDavid du Colombier ADD R1, R2 79*3de6a9c0SDavid du Colombier MOVW (R2), R(MACH) /* m = machaddr[cpuid] */ 80*3de6a9c0SDavid du Colombier CMP $0, R(MACH) 81*3de6a9c0SDavid du Colombier MOVW.EQ $MACHADDR, R0 /* paranoia: use MACHADDR if 0 */ 82*3de6a9c0SDavid du Colombier MOVW 8(R(MACH)), R(USER) /* up = m->proc */ 83*3de6a9c0SDavid du Colombier 84*3de6a9c0SDavid du Colombier MOVW ((NREGS+1)*4)(R13), R2 /* saved SPSR (user mode) */ 85*3de6a9c0SDavid du Colombier 86*3de6a9c0SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 87*3de6a9c0SDavid du Colombier SUB $8, R13 /* space for argument+link */ 88*3de6a9c0SDavid du Colombier 89*3de6a9c0SDavid du Colombier BL syscall(SB) 90*3de6a9c0SDavid du Colombier /* 91*3de6a9c0SDavid du Colombier * caller saves on plan 9, so registers other than 9, 10, 13 & 14 92*3de6a9c0SDavid du Colombier * may have been trashed when we get here. 93*3de6a9c0SDavid du Colombier */ 94*3de6a9c0SDavid du Colombier 95*3de6a9c0SDavid du Colombier MOVW $setR12(SB), R12 /* reload kernel's SB */ 96*3de6a9c0SDavid du Colombier 97*3de6a9c0SDavid du Colombier ADD $(8+4*NREGS), R13 /* make r13 point to ureg->type */ 98*3de6a9c0SDavid du Colombier 99*3de6a9c0SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 100*3de6a9c0SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 101*3de6a9c0SDavid du Colombier/* 102*3de6a9c0SDavid du Colombier * return from user-mode exception. 103*3de6a9c0SDavid du Colombier * expects new SPSR in R0. R13 must point to ureg->type. 104*3de6a9c0SDavid du Colombier */ 105*3de6a9c0SDavid du Colombier_rfue: 106*3de6a9c0SDavid du ColombierTEXT rfue(SB), 1, $-4 107*3de6a9c0SDavid du Colombier MOVW R0, SPSR /* ... */ 108*3de6a9c0SDavid du Colombier 109*3de6a9c0SDavid du Colombier /* 110*3de6a9c0SDavid du Colombier * order on stack is type, psr, pc, but RFEV7 needs pc, psr. 111*3de6a9c0SDavid du Colombier * step on type and previous word to hold temporary values. 112*3de6a9c0SDavid du Colombier * we could instead change the order in which psr & pc are pushed. 113*3de6a9c0SDavid du Colombier */ 114*3de6a9c0SDavid du Colombier MOVW 4(R13), R1 /* psr */ 115*3de6a9c0SDavid du Colombier MOVW 8(R13), R2 /* pc */ 116*3de6a9c0SDavid du Colombier MOVW R2, 4(R13) /* pc */ 117*3de6a9c0SDavid du Colombier MOVW R1, 8(R13) /* psr */ 118*3de6a9c0SDavid du Colombier 119*3de6a9c0SDavid du Colombier MOVM.DB.S (R13), [R0-R14] /* restore user registers */ 120*3de6a9c0SDavid du Colombier ADD $4, R13 /* pop type, sp -> pc */ 121*3de6a9c0SDavid du Colombier RFEV7W(13) 122*3de6a9c0SDavid du Colombier 123*3de6a9c0SDavid du Colombier 124*3de6a9c0SDavid du ColombierTEXT _vund(SB), 1, $-4 /* undefined */ 125*3de6a9c0SDavid du Colombier /* sp is m->sund */ 126*3de6a9c0SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 127*3de6a9c0SDavid du Colombier MOVW $PsrMund, R0 128*3de6a9c0SDavid du Colombier B _vswitch 129*3de6a9c0SDavid du Colombier 130*3de6a9c0SDavid du ColombierTEXT _vpabt(SB), 1, $-4 /* prefetch abort */ 131*3de6a9c0SDavid du Colombier /* sp is m->sabt */ 132*3de6a9c0SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 133*3de6a9c0SDavid du Colombier MOVW $PsrMabt, R0 /* r0 = type */ 134*3de6a9c0SDavid du Colombier B _vswitch 135*3de6a9c0SDavid du Colombier 136*3de6a9c0SDavid du ColombierTEXT _vdabt(SB), 1, $-4 /* data abort */ 137*3de6a9c0SDavid du Colombier /* sp is m->sabt */ 138*3de6a9c0SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 139*3de6a9c0SDavid du Colombier MOVW $(PsrMabt+1), R0 /* r0 = type */ 140*3de6a9c0SDavid du Colombier B _vswitch 141*3de6a9c0SDavid du Colombier 142*3de6a9c0SDavid du ColombierTEXT _virq(SB), 1, $-4 /* IRQ */ 143*3de6a9c0SDavid du Colombier /* sp is m->sirq */ 144*3de6a9c0SDavid du Colombier MOVM.IA [R0-R4], (R13) /* free some working space */ 145*3de6a9c0SDavid du Colombier MOVW $PsrMirq, R0 /* r0 = type */ 146*3de6a9c0SDavid du Colombier B _vswitch 147*3de6a9c0SDavid du Colombier 148*3de6a9c0SDavid du Colombier /* 149*3de6a9c0SDavid du Colombier * come here with type in R0 and R13 pointing above saved [r0-r4]. 150*3de6a9c0SDavid du Colombier * we'll switch to SVC mode and then call trap. 151*3de6a9c0SDavid du Colombier */ 152*3de6a9c0SDavid du Colombier_vswitch: 153*3de6a9c0SDavid du Colombier// TEXT _vswtch(SB), 1, $-4 /* make symbol visible to debuggers */ 154*3de6a9c0SDavid du Colombier CLREX 155*3de6a9c0SDavid du Colombier BARRIERS 156*3de6a9c0SDavid du Colombier MOVW SPSR, R1 /* save SPSR for ureg */ 157*3de6a9c0SDavid du Colombier /* 158*3de6a9c0SDavid du Colombier * R12 needs to be set before using PsrMbz, so BIGENDCHECK code has 159*3de6a9c0SDavid du Colombier * been moved below. 160*3de6a9c0SDavid du Colombier */ 161*3de6a9c0SDavid du Colombier MOVW R14, R2 /* save interrupted pc for ureg */ 162*3de6a9c0SDavid du Colombier MOVW R13, R3 /* save pointer to where the original [R0-R4] are */ 163*3de6a9c0SDavid du Colombier 164*3de6a9c0SDavid du Colombier /* 165*3de6a9c0SDavid du Colombier * switch processor to svc mode. this switches the banked registers 166*3de6a9c0SDavid du Colombier * (r13 [sp] and r14 [link]) to those of svc mode (so we must be sure 167*3de6a9c0SDavid du Colombier * to never get here already in svc mode). 168*3de6a9c0SDavid du Colombier */ 169*3de6a9c0SDavid du Colombier CPSMODE(PsrMsvc) /* switch! */ 170*3de6a9c0SDavid du Colombier CPSID 171*3de6a9c0SDavid du Colombier 172*3de6a9c0SDavid du Colombier AND.S $0xf, R1, R4 /* interrupted code kernel or user? */ 173*3de6a9c0SDavid du Colombier BEQ _userexcep 174*3de6a9c0SDavid du Colombier 175*3de6a9c0SDavid du Colombier /* 176*3de6a9c0SDavid du Colombier * here for trap from SVC mode 177*3de6a9c0SDavid du Colombier */ 178*3de6a9c0SDavid du Colombier 179*3de6a9c0SDavid du Colombier /* push ureg->{type, psr, pc} onto Msvc stack. 180*3de6a9c0SDavid du Colombier * r13 points to ureg->type after. 181*3de6a9c0SDavid du Colombier */ 182*3de6a9c0SDavid du Colombier MOVM.DB.W [R0-R2], (R13) 183*3de6a9c0SDavid du Colombier MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ 184*3de6a9c0SDavid du Colombier 185*3de6a9c0SDavid du Colombier /* 186*3de6a9c0SDavid du Colombier * avoid the ambiguity described in notes/movm.w. 187*3de6a9c0SDavid du Colombier * In order to get a predictable value in R13 after the stores, 188*3de6a9c0SDavid du Colombier * separate the store-multiple from the stack-pointer adjustment. 189*3de6a9c0SDavid du Colombier * We'll assume that the old value of R13 should be stored on the stack. 190*3de6a9c0SDavid du Colombier */ 191*3de6a9c0SDavid du Colombier /* save kernel level registers, at end r13 points to ureg */ 192*3de6a9c0SDavid du Colombier MOVM.DB [R0-R14], (R13) 193*3de6a9c0SDavid du Colombier SUB $(NREGS*4), R13 /* SP now points to saved R0 */ 194*3de6a9c0SDavid du Colombier 195*3de6a9c0SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 196*3de6a9c0SDavid du Colombier /* previous mode was svc, so the saved spsr should be sane. */ 197*3de6a9c0SDavid du Colombier MOVW ((NREGS+1)*4)(R13), R1 198*3de6a9c0SDavid du Colombier 199*3de6a9c0SDavid du Colombier MOVM.IA (R13), [R0-R8] /* restore a few user registers */ 200*3de6a9c0SDavid du Colombier 201*3de6a9c0SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 202*3de6a9c0SDavid du Colombier SUB $(4*2), R13 /* space for argument+link (for debugger) */ 203*3de6a9c0SDavid du Colombier MOVW $0xdeaddead, R11 /* marker */ 204*3de6a9c0SDavid du Colombier 205*3de6a9c0SDavid du Colombier BL trap(SB) /* trap(ureg) */ 206*3de6a9c0SDavid du Colombier /* 207*3de6a9c0SDavid du Colombier * caller saves on plan 9, so registers other than 9, 10, 13 & 14 208*3de6a9c0SDavid du Colombier * may have been trashed when we get here. 209*3de6a9c0SDavid du Colombier */ 210*3de6a9c0SDavid du Colombier 211*3de6a9c0SDavid du Colombier MOVW $setR12(SB), R12 /* reload kernel's SB */ 212*3de6a9c0SDavid du Colombier 213*3de6a9c0SDavid du Colombier ADD $(4*2+4*NREGS), R13 /* make r13 point to ureg->type */ 214*3de6a9c0SDavid du Colombier 215*3de6a9c0SDavid du Colombier /* 216*3de6a9c0SDavid du Colombier * if we interrupted a previous trap's handler and are now 217*3de6a9c0SDavid du Colombier * returning to it, we need to propagate the current R(MACH) (R10) 218*3de6a9c0SDavid du Colombier * by overriding the saved one on the stack, since we may have 219*3de6a9c0SDavid du Colombier * been rescheduled and be on a different processor now than 220*3de6a9c0SDavid du Colombier * at entry. 221*3de6a9c0SDavid du Colombier */ 222*3de6a9c0SDavid du Colombier MOVW R(MACH), (-(NREGS-MACH)*4)(R13) /* restore current cpu's MACH */ 223*3de6a9c0SDavid du Colombier 224*3de6a9c0SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 225*3de6a9c0SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 226*3de6a9c0SDavid du Colombier 227*3de6a9c0SDavid du Colombier /* return from kernel-mode exception */ 228*3de6a9c0SDavid du Colombier MOVW R0, SPSR /* ... */ 229*3de6a9c0SDavid du Colombier 230*3de6a9c0SDavid du Colombier /* 231*3de6a9c0SDavid du Colombier * order on stack is type, psr, pc, but RFEV7 needs pc, psr. 232*3de6a9c0SDavid du Colombier * step on type and previous word to hold temporary values. 233*3de6a9c0SDavid du Colombier * we could instead change the order in which psr & pc are pushed. 234*3de6a9c0SDavid du Colombier */ 235*3de6a9c0SDavid du Colombier MOVW 4(R13), R1 /* psr */ 236*3de6a9c0SDavid du Colombier MOVW 8(R13), R2 /* pc */ 237*3de6a9c0SDavid du Colombier MOVW R2, 4(R13) /* pc */ 238*3de6a9c0SDavid du Colombier MOVW R1, 8(R13) /* psr */ 239*3de6a9c0SDavid du Colombier 240*3de6a9c0SDavid du Colombier /* restore kernel regs other than SP; we're using it */ 241*3de6a9c0SDavid du Colombier SUB $(NREGS*4), R13 242*3de6a9c0SDavid du Colombier MOVM.IA.W (R13), [R0-R12] 243*3de6a9c0SDavid du Colombier ADD $4, R13 /* skip saved kernel SP */ 244*3de6a9c0SDavid du Colombier MOVM.IA.W (R13), [R14] 245*3de6a9c0SDavid du Colombier ADD $4, R13 /* pop type, sp -> pc */ 246*3de6a9c0SDavid du Colombier BARRIERS 247*3de6a9c0SDavid du Colombier RFEV7W(13) 248*3de6a9c0SDavid du Colombier 249*3de6a9c0SDavid du Colombier /* 250*3de6a9c0SDavid du Colombier * here for trap from USER mode 251*3de6a9c0SDavid du Colombier */ 252*3de6a9c0SDavid du Colombier_userexcep: 253*3de6a9c0SDavid du Colombier MOVM.DB.W [R0-R2], (R13) /* set ureg->{type, psr, pc}; r13 points to ureg->type */ 254*3de6a9c0SDavid du Colombier MOVM.IA (R3), [R0-R4] /* restore [R0-R4] from previous mode's stack */ 255*3de6a9c0SDavid du Colombier 256*3de6a9c0SDavid du Colombier /* avoid the ambiguity described in notes/movm.w. */ 257*3de6a9c0SDavid du Colombier MOVM.DB.S [R0-R14], (R13) /* save kernel level registers */ 258*3de6a9c0SDavid du Colombier SUB $(NREGS*4), R13 /* r13 now points to ureg */ 259*3de6a9c0SDavid du Colombier 260*3de6a9c0SDavid du Colombier MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */ 261*3de6a9c0SDavid du Colombier 262*3de6a9c0SDavid du Colombier /* 263*3de6a9c0SDavid du Colombier * set up m and up registers since user registers could contain anything 264*3de6a9c0SDavid du Colombier */ 265*3de6a9c0SDavid du Colombier CPUID(R1) 266*3de6a9c0SDavid du Colombier SLL $2, R1 /* convert to word index */ 267*3de6a9c0SDavid du Colombier MOVW $machaddr(SB), R2 268*3de6a9c0SDavid du Colombier ADD R1, R2 269*3de6a9c0SDavid du Colombier MOVW (R2), R(MACH) /* m = machaddr[cpuid] */ 270*3de6a9c0SDavid du Colombier CMP $0, R(MACH) 271*3de6a9c0SDavid du Colombier MOVW.EQ $MACHADDR, R0 /* paranoia: use MACHADDR if 0 */ 272*3de6a9c0SDavid du Colombier MOVW 8(R(MACH)), R(USER) /* up = m->proc */ 273*3de6a9c0SDavid du Colombier 274*3de6a9c0SDavid du Colombier MOVW ((NREGS+1)*4)(R13), R2 /* saved SPSR */ 275*3de6a9c0SDavid du Colombier 276*3de6a9c0SDavid du Colombier MOVW R13, R0 /* first arg is pointer to ureg */ 277*3de6a9c0SDavid du Colombier SUB $(4*2), R13 /* space for argument+link (for debugger) */ 278*3de6a9c0SDavid du Colombier 279*3de6a9c0SDavid du Colombier BL trap(SB) /* trap(ureg) */ 280*3de6a9c0SDavid du Colombier /* 281*3de6a9c0SDavid du Colombier * caller saves on plan 9, so registers other than 9, 10, 13 & 14 282*3de6a9c0SDavid du Colombier * may have been trashed when we get here. 283*3de6a9c0SDavid du Colombier */ 284*3de6a9c0SDavid du Colombier 285*3de6a9c0SDavid du Colombier ADD $(4*2+4*NREGS), R13 /* make r13 point to ureg->type */ 286*3de6a9c0SDavid du Colombier 287*3de6a9c0SDavid du Colombier MOVW 8(R13), R14 /* restore link */ 288*3de6a9c0SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 289*3de6a9c0SDavid du Colombier 290*3de6a9c0SDavid du Colombier MOVW 4(R13), R0 /* restore SPSR */ 291*3de6a9c0SDavid du Colombier B _rfue 292*3de6a9c0SDavid du Colombier 293*3de6a9c0SDavid du Colombier 294*3de6a9c0SDavid du ColombierTEXT _vfiq(SB), 1, $-4 /* FIQ */ 295*3de6a9c0SDavid du Colombier PUTC('?') 296*3de6a9c0SDavid du Colombier PUTC('f') 297*3de6a9c0SDavid du Colombier PUTC('i') 298*3de6a9c0SDavid du Colombier PUTC('q') 299*3de6a9c0SDavid du Colombier RFE /* FIQ is special, ignore it for now */ 300*3de6a9c0SDavid du Colombier 301*3de6a9c0SDavid du ColombierTEXT _vhype(SB), 1, $-4 302*3de6a9c0SDavid du Colombier PUTC('?') 303*3de6a9c0SDavid du Colombier PUTC('h') 304*3de6a9c0SDavid du Colombier PUTC('y') 305*3de6a9c0SDavid du Colombier PUTC('p') 306*3de6a9c0SDavid du Colombier RFE 307*3de6a9c0SDavid du Colombier 308*3de6a9c0SDavid du Colombier/* 309*3de6a9c0SDavid du Colombier * set the stack value for the mode passed in R0 310*3de6a9c0SDavid du Colombier */ 311*3de6a9c0SDavid du ColombierTEXT setr13(SB), 1, $-4 312*3de6a9c0SDavid du Colombier MOVW 4(FP), R1 313*3de6a9c0SDavid du Colombier 314*3de6a9c0SDavid du Colombier MOVW CPSR, R2 315*3de6a9c0SDavid du Colombier BIC $(PsrMask|PsrMbz), R2, R3 316*3de6a9c0SDavid du Colombier ORR $(PsrDirq|PsrDfiq), R3 317*3de6a9c0SDavid du Colombier ORR R0, R3 318*3de6a9c0SDavid du Colombier 319*3de6a9c0SDavid du Colombier MOVW R3, CPSR /* switch to new mode */ 320*3de6a9c0SDavid du Colombier 321*3de6a9c0SDavid du Colombier MOVW R13, R0 /* return old sp */ 322*3de6a9c0SDavid du Colombier MOVW R1, R13 /* install new one */ 323*3de6a9c0SDavid du Colombier 324*3de6a9c0SDavid du Colombier MOVW R2, CPSR /* switch back to old mode */ 325*3de6a9c0SDavid du Colombier RET 326