xref: /inferno-os/os/boot/rpcg/trap.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth #include "boot.h"
2*74a4d8c2SCharles.Forsyth 
3*74a4d8c2SCharles.Forsyth enum
4*74a4d8c2SCharles.Forsyth {
5*74a4d8c2SCharles.Forsyth 	Maxhandler=	32+16,		/* max number of interrupt handlers */
6*74a4d8c2SCharles.Forsyth };
7*74a4d8c2SCharles.Forsyth 
8*74a4d8c2SCharles.Forsyth typedef struct Handler	Handler;
9*74a4d8c2SCharles.Forsyth struct Handler
10*74a4d8c2SCharles.Forsyth {
11*74a4d8c2SCharles.Forsyth 	void	(*r)(Ureg*, void*);
12*74a4d8c2SCharles.Forsyth 	void	*arg;
13*74a4d8c2SCharles.Forsyth 	Handler	*next;
14*74a4d8c2SCharles.Forsyth 	int	edge;
15*74a4d8c2SCharles.Forsyth };
16*74a4d8c2SCharles.Forsyth 
17*74a4d8c2SCharles.Forsyth struct
18*74a4d8c2SCharles.Forsyth {
19*74a4d8c2SCharles.Forsyth 	Handler	*ivec[128];
20*74a4d8c2SCharles.Forsyth 	Handler	h[Maxhandler];
21*74a4d8c2SCharles.Forsyth 	int	free;
22*74a4d8c2SCharles.Forsyth } halloc;
23*74a4d8c2SCharles.Forsyth 
24*74a4d8c2SCharles.Forsyth char	*excname[] = {
25*74a4d8c2SCharles.Forsyth 	"reserved 0",
26*74a4d8c2SCharles.Forsyth 	"system reset",
27*74a4d8c2SCharles.Forsyth 	"machine check",
28*74a4d8c2SCharles.Forsyth 	"data access",
29*74a4d8c2SCharles.Forsyth 	"instruction access",
30*74a4d8c2SCharles.Forsyth 	"external interrupt",
31*74a4d8c2SCharles.Forsyth 	"alignment",
32*74a4d8c2SCharles.Forsyth 	"program exception",
33*74a4d8c2SCharles.Forsyth 	"floating-point unavailable",
34*74a4d8c2SCharles.Forsyth 	"decrementer",
35*74a4d8c2SCharles.Forsyth 	"reserved A",
36*74a4d8c2SCharles.Forsyth 	"reserved B",
37*74a4d8c2SCharles.Forsyth 	"system call",
38*74a4d8c2SCharles.Forsyth 	"trace trap",
39*74a4d8c2SCharles.Forsyth 	"floating point assist",
40*74a4d8c2SCharles.Forsyth 	"reserved F",
41*74a4d8c2SCharles.Forsyth 	"software emulation",
42*74a4d8c2SCharles.Forsyth 	"ITLB miss",
43*74a4d8c2SCharles.Forsyth 	"DTLB miss",
44*74a4d8c2SCharles.Forsyth 	"ITLB error",
45*74a4d8c2SCharles.Forsyth 	"DTLB error",
46*74a4d8c2SCharles.Forsyth };
47*74a4d8c2SCharles.Forsyth 
48*74a4d8c2SCharles.Forsyth char *regname[]={
49*74a4d8c2SCharles.Forsyth 	"CAUSE",	"SRR1",
50*74a4d8c2SCharles.Forsyth 	"PC",		"GOK",
51*74a4d8c2SCharles.Forsyth 	"LR",		"CR",
52*74a4d8c2SCharles.Forsyth 	"XER",	"CTR",
53*74a4d8c2SCharles.Forsyth 	"R0",		"R1",
54*74a4d8c2SCharles.Forsyth 	"R2",		"R3",
55*74a4d8c2SCharles.Forsyth 	"R4",		"R5",
56*74a4d8c2SCharles.Forsyth 	"R6",		"R7",
57*74a4d8c2SCharles.Forsyth 	"R8",		"R9",
58*74a4d8c2SCharles.Forsyth 	"R10",	"R11",
59*74a4d8c2SCharles.Forsyth 	"R12",	"R13",
60*74a4d8c2SCharles.Forsyth 	"R14",	"R15",
61*74a4d8c2SCharles.Forsyth 	"R16",	"R17",
62*74a4d8c2SCharles.Forsyth 	"R18",	"R19",
63*74a4d8c2SCharles.Forsyth 	"R20",	"R21",
64*74a4d8c2SCharles.Forsyth 	"R22",	"R23",
65*74a4d8c2SCharles.Forsyth 	"R24",	"R25",
66*74a4d8c2SCharles.Forsyth 	"R26",	"R27",
67*74a4d8c2SCharles.Forsyth 	"R28",	"R29",
68*74a4d8c2SCharles.Forsyth 	"R30",	"R31",
69*74a4d8c2SCharles.Forsyth };
70*74a4d8c2SCharles.Forsyth 
71*74a4d8c2SCharles.Forsyth static	void	intr(Ureg*);
72*74a4d8c2SCharles.Forsyth 
73*74a4d8c2SCharles.Forsyth void
sethvec(int v,void (* r)(void))74*74a4d8c2SCharles.Forsyth sethvec(int v, void (*r)(void))
75*74a4d8c2SCharles.Forsyth {
76*74a4d8c2SCharles.Forsyth 	ulong *vp, pa, o;
77*74a4d8c2SCharles.Forsyth 
78*74a4d8c2SCharles.Forsyth 	if((ulong)r & 3)
79*74a4d8c2SCharles.Forsyth 		panic("sethvec");
80*74a4d8c2SCharles.Forsyth 	vp = (ulong*)KADDR(v);
81*74a4d8c2SCharles.Forsyth 	vp[0] = 0x7c1043a6;	/* MOVW R0, SPR(SPRG0) */
82*74a4d8c2SCharles.Forsyth 	vp[1] = 0x7c0802a6;	/* MOVW LR, R0 */
83*74a4d8c2SCharles.Forsyth 	vp[2] = 0x7c1243a6;	/* MOVW R0, SPR(SPRG2) */
84*74a4d8c2SCharles.Forsyth 	pa = PADDR(r);
85*74a4d8c2SCharles.Forsyth 	o = pa >> 25;
86*74a4d8c2SCharles.Forsyth 	if(o != 0 && o != 0x7F){
87*74a4d8c2SCharles.Forsyth 		/* a branch too far: running from ROM */
88*74a4d8c2SCharles.Forsyth 		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
89*74a4d8c2SCharles.Forsyth 		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
90*74a4d8c2SCharles.Forsyth 		vp[5] = 0x7c0803a6;	/* MOVW	R0, LR */
91*74a4d8c2SCharles.Forsyth 		vp[6] = 0x4e800021;	/* BL (LR) */
92*74a4d8c2SCharles.Forsyth 	}else
93*74a4d8c2SCharles.Forsyth 		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
94*74a4d8c2SCharles.Forsyth }
95*74a4d8c2SCharles.Forsyth 
96*74a4d8c2SCharles.Forsyth #define	LEV(n)	(((n)<<1)|1)
97*74a4d8c2SCharles.Forsyth #define	IRQ(n)	(((n)<<1)|0)
98*74a4d8c2SCharles.Forsyth 
99*74a4d8c2SCharles.Forsyth void
setvec(int v,void (* r)(Ureg *,void *),void * arg)100*74a4d8c2SCharles.Forsyth setvec(int v, void (*r)(Ureg*, void*), void *arg)
101*74a4d8c2SCharles.Forsyth {
102*74a4d8c2SCharles.Forsyth 	Handler *h;
103*74a4d8c2SCharles.Forsyth 	IMM *io;
104*74a4d8c2SCharles.Forsyth 
105*74a4d8c2SCharles.Forsyth 	if(halloc.free >= Maxhandler)
106*74a4d8c2SCharles.Forsyth 		panic("out of interrupt handlers");
107*74a4d8c2SCharles.Forsyth 	v -= VectorPIC;
108*74a4d8c2SCharles.Forsyth 	h = &halloc.h[halloc.free++];
109*74a4d8c2SCharles.Forsyth 	h->next = halloc.ivec[v];
110*74a4d8c2SCharles.Forsyth 	h->r = r;
111*74a4d8c2SCharles.Forsyth 	h->arg = arg;
112*74a4d8c2SCharles.Forsyth 	halloc.ivec[v] = h;
113*74a4d8c2SCharles.Forsyth 
114*74a4d8c2SCharles.Forsyth 	/*
115*74a4d8c2SCharles.Forsyth 	 * enable corresponding interrupt in SIU/CPM
116*74a4d8c2SCharles.Forsyth 	 */
117*74a4d8c2SCharles.Forsyth 
118*74a4d8c2SCharles.Forsyth 	io = m->iomem;
119*74a4d8c2SCharles.Forsyth 	if(v >= VectorCPIC){
120*74a4d8c2SCharles.Forsyth 		v -= VectorCPIC;
121*74a4d8c2SCharles.Forsyth 		io->cimr |= 1<<(v&0x1F);
122*74a4d8c2SCharles.Forsyth 	}
123*74a4d8c2SCharles.Forsyth 	else if(v >= VectorIRQ)
124*74a4d8c2SCharles.Forsyth 		io->simask |= 1<<(31-IRQ(v&7));
125*74a4d8c2SCharles.Forsyth 	else
126*74a4d8c2SCharles.Forsyth 		io->simask |= 1<<(31-LEV(v));
127*74a4d8c2SCharles.Forsyth }
128*74a4d8c2SCharles.Forsyth 
129*74a4d8c2SCharles.Forsyth void
trapinit(void)130*74a4d8c2SCharles.Forsyth trapinit(void)
131*74a4d8c2SCharles.Forsyth {
132*74a4d8c2SCharles.Forsyth 	int i;
133*74a4d8c2SCharles.Forsyth 	IMM *io;
134*74a4d8c2SCharles.Forsyth 
135*74a4d8c2SCharles.Forsyth 	io = m->iomem;
136*74a4d8c2SCharles.Forsyth 	io->sypcr &= ~(3<<2);	/* disable watchdog (821/823) */
137*74a4d8c2SCharles.Forsyth 	io->simask = 0;	/* mask all */
138*74a4d8c2SCharles.Forsyth 	io->siel = ~0;	/* edge sensitive, wake on all */
139*74a4d8c2SCharles.Forsyth 	io->cicr = 0;	/* disable CPM interrupts */
140*74a4d8c2SCharles.Forsyth 	io->cipr = ~0;	/* clear all interrupts */
141*74a4d8c2SCharles.Forsyth 	io->cimr = 0;	/* mask all events */
142*74a4d8c2SCharles.Forsyth 	io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8);
143*74a4d8c2SCharles.Forsyth 	io->cicr |= 1 << 7;	/* enable */
144*74a4d8c2SCharles.Forsyth 	io->tbscrk = KEEP_ALIVE_KEY;
145*74a4d8c2SCharles.Forsyth 	io->tbscr = 1;	/* TBE */
146*74a4d8c2SCharles.Forsyth 	io->simask |= 1<<(31-LEV(CPIClevel));	/* CPM's level */
147*74a4d8c2SCharles.Forsyth 	io->tbk = KEEP_ALIVE_KEY;
148*74a4d8c2SCharles.Forsyth 	eieio();
149*74a4d8c2SCharles.Forsyth 	putdec(~0);
150*74a4d8c2SCharles.Forsyth 
151*74a4d8c2SCharles.Forsyth 	/*
152*74a4d8c2SCharles.Forsyth 	 * set all exceptions to trap
153*74a4d8c2SCharles.Forsyth 	 */
154*74a4d8c2SCharles.Forsyth 	for(i = 0x0; i < 0x3000; i += 0x100)
155*74a4d8c2SCharles.Forsyth 		sethvec(i, exception);
156*74a4d8c2SCharles.Forsyth }
157*74a4d8c2SCharles.Forsyth 
158*74a4d8c2SCharles.Forsyth void
dumpregs(Ureg * ur)159*74a4d8c2SCharles.Forsyth dumpregs(Ureg *ur)
160*74a4d8c2SCharles.Forsyth {
161*74a4d8c2SCharles.Forsyth 	int i;
162*74a4d8c2SCharles.Forsyth 	ulong *l;
163*74a4d8c2SCharles.Forsyth 	l = &ur->cause;
164*74a4d8c2SCharles.Forsyth 	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
165*74a4d8c2SCharles.Forsyth 		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
166*74a4d8c2SCharles.Forsyth }
167*74a4d8c2SCharles.Forsyth 
168*74a4d8c2SCharles.Forsyth void
trap(Ureg * ur)169*74a4d8c2SCharles.Forsyth trap(Ureg *ur)
170*74a4d8c2SCharles.Forsyth {
171*74a4d8c2SCharles.Forsyth 	int c;
172*74a4d8c2SCharles.Forsyth 
173*74a4d8c2SCharles.Forsyth 	c = ur->cause >> 8;
174*74a4d8c2SCharles.Forsyth 	switch(c){
175*74a4d8c2SCharles.Forsyth 	default:
176*74a4d8c2SCharles.Forsyth 		{extern int predawn; predawn = 1;}
177*74a4d8c2SCharles.Forsyth 		if(c < 0 || c >= nelem(excname))
178*74a4d8c2SCharles.Forsyth 			print("exception/interrupt #%x\n", c);
179*74a4d8c2SCharles.Forsyth 		else
180*74a4d8c2SCharles.Forsyth 			print("exception %s\n", excname[c]);
181*74a4d8c2SCharles.Forsyth 		dumpregs(ur);
182*74a4d8c2SCharles.Forsyth 		/* spllo(); */
183*74a4d8c2SCharles.Forsyth 		print("^P to reset\n");
184*74a4d8c2SCharles.Forsyth 		for(;;)
185*74a4d8c2SCharles.Forsyth 			;
186*74a4d8c2SCharles.Forsyth 
187*74a4d8c2SCharles.Forsyth 	case 0x09:	/* decrementer */
188*74a4d8c2SCharles.Forsyth 		clockintr(ur, 0);
189*74a4d8c2SCharles.Forsyth 		return;
190*74a4d8c2SCharles.Forsyth 
191*74a4d8c2SCharles.Forsyth 	case 0x05:	/* external interrupt */
192*74a4d8c2SCharles.Forsyth 		intr(ur);
193*74a4d8c2SCharles.Forsyth 		break;
194*74a4d8c2SCharles.Forsyth 	}
195*74a4d8c2SCharles.Forsyth }
196*74a4d8c2SCharles.Forsyth 
197*74a4d8c2SCharles.Forsyth static void
intr(Ureg * ur)198*74a4d8c2SCharles.Forsyth intr(Ureg *ur)
199*74a4d8c2SCharles.Forsyth {
200*74a4d8c2SCharles.Forsyth 	int b, v;
201*74a4d8c2SCharles.Forsyth 	Handler *h;
202*74a4d8c2SCharles.Forsyth 	IMM *io;
203*74a4d8c2SCharles.Forsyth 
204*74a4d8c2SCharles.Forsyth 	io = m->iomem;
205*74a4d8c2SCharles.Forsyth 	b = io->sivec>>2;
206*74a4d8c2SCharles.Forsyth 	v = b>>1;
207*74a4d8c2SCharles.Forsyth 	if(b & 1) {
208*74a4d8c2SCharles.Forsyth 		if(v == CPIClevel){
209*74a4d8c2SCharles.Forsyth 			io->civr = 1;
210*74a4d8c2SCharles.Forsyth 			eieio();
211*74a4d8c2SCharles.Forsyth 			v = VectorCPIC+(io->civr>>11);
212*74a4d8c2SCharles.Forsyth 		}
213*74a4d8c2SCharles.Forsyth 	}else
214*74a4d8c2SCharles.Forsyth 		v += VectorIRQ;
215*74a4d8c2SCharles.Forsyth 	h = halloc.ivec[v];
216*74a4d8c2SCharles.Forsyth 	if(h == nil){
217*74a4d8c2SCharles.Forsyth 		for(;;)
218*74a4d8c2SCharles.Forsyth 			;
219*74a4d8c2SCharles.Forsyth 		//print("unknown interrupt %d pc=0x%lux\n", v, ur->pc);
220*74a4d8c2SCharles.Forsyth 		return;
221*74a4d8c2SCharles.Forsyth 	}
222*74a4d8c2SCharles.Forsyth 	if(h->edge)
223*74a4d8c2SCharles.Forsyth 		io->sipend |= 1<<(31-b);
224*74a4d8c2SCharles.Forsyth 	/*
225*74a4d8c2SCharles.Forsyth 	 *  call the interrupt handlers
226*74a4d8c2SCharles.Forsyth 	 */
227*74a4d8c2SCharles.Forsyth 	do {
228*74a4d8c2SCharles.Forsyth 		(*h->r)(ur, h->arg);
229*74a4d8c2SCharles.Forsyth 		h = h->next;
230*74a4d8c2SCharles.Forsyth 	} while(h != nil);
231*74a4d8c2SCharles.Forsyth 	if(v >= VectorCPIC)
232*74a4d8c2SCharles.Forsyth 		io->cisr |= 1<<(v-VectorCPIC);
233*74a4d8c2SCharles.Forsyth }
234