xref: /plan9/sys/src/9/bcm/lexception.s (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
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