xref: /plan9/sys/src/9/teg2/lexception.s (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
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