xref: /plan9-contrib/sys/src/9/rb/trap.c (revision dc100ed4690b2e24ee94b6fe674abc915c477a6d)
1f43f8ee6SDavid du Colombier /*
2f43f8ee6SDavid du Colombier  * traps, exceptions, faults and interrupts on ar7161
3f43f8ee6SDavid du Colombier  */
4f43f8ee6SDavid du Colombier #include	"u.h"
5f43f8ee6SDavid du Colombier #include	"../port/lib.h"
6f43f8ee6SDavid du Colombier #include	"mem.h"
7f43f8ee6SDavid du Colombier #include	"dat.h"
8f43f8ee6SDavid du Colombier #include	"fns.h"
9f43f8ee6SDavid du Colombier #include	"ureg.h"
10f43f8ee6SDavid du Colombier #include	"io.h"
11f43f8ee6SDavid du Colombier #include	<tos.h>
12f43f8ee6SDavid du Colombier #include	"../port/error.h"
13f43f8ee6SDavid du Colombier 
14f43f8ee6SDavid du Colombier #define setstatus(v)	/* experiment: delete this to enable recursive traps */
15f43f8ee6SDavid du Colombier 
16f43f8ee6SDavid du Colombier typedef struct Handler Handler;
17f43f8ee6SDavid du Colombier 
18f43f8ee6SDavid du Colombier struct Handler {
19f43f8ee6SDavid du Colombier 	void	(*handler)(void *);
20f43f8ee6SDavid du Colombier 	void	*arg;
21f43f8ee6SDavid du Colombier 	Handler	*next;			/* at this interrupt level */
22f43f8ee6SDavid du Colombier 	ulong	intrs;
23f43f8ee6SDavid du Colombier };
24f43f8ee6SDavid du Colombier 
25f43f8ee6SDavid du Colombier ulong offintrs;
26f43f8ee6SDavid du Colombier ulong intrcauses[ILmax+1];
27f43f8ee6SDavid du Colombier 
28f43f8ee6SDavid du Colombier int	intr(Ureg*);
29f43f8ee6SDavid du Colombier void	kernfault(Ureg*, int);
30f43f8ee6SDavid du Colombier void	noted(Ureg*, Ureg**, ulong);
31f43f8ee6SDavid du Colombier void	rfnote(Ureg**);
32f43f8ee6SDavid du Colombier 
33f43f8ee6SDavid du Colombier char *excname[] =
34f43f8ee6SDavid du Colombier {
35f43f8ee6SDavid du Colombier 	"trap: external interrupt",
36f43f8ee6SDavid du Colombier 	"trap: TLB modification (store to unwritable)",
37f43f8ee6SDavid du Colombier 	"trap: TLB miss (load or fetch)",
38f43f8ee6SDavid du Colombier 	"trap: TLB miss (store)",
39f43f8ee6SDavid du Colombier 	"trap: address error (load or fetch)",
40f43f8ee6SDavid du Colombier 	"trap: address error (store)",
41f43f8ee6SDavid du Colombier 	"trap: bus error (fetch)",
42f43f8ee6SDavid du Colombier 	"trap: bus error (data load or store)",
43f43f8ee6SDavid du Colombier 	"trap: system call",
44f43f8ee6SDavid du Colombier 	"breakpoint",
45f43f8ee6SDavid du Colombier 	"trap: reserved instruction",
46f43f8ee6SDavid du Colombier 	"trap: coprocessor unusable",
47f43f8ee6SDavid du Colombier 	"trap: arithmetic overflow",
48f43f8ee6SDavid du Colombier 	"trap: TRAP exception",
49f43f8ee6SDavid du Colombier 	"trap: VCE (instruction)",
50f43f8ee6SDavid du Colombier 	"trap: floating-point exception",
51f43f8ee6SDavid du Colombier 	"trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
52f43f8ee6SDavid du Colombier 	"trap: corextend unusable",
53f43f8ee6SDavid du Colombier 	"trap: precise coprocessor 2 exception",
54f43f8ee6SDavid du Colombier 	"trap: TLB read-inhibit",
55f43f8ee6SDavid du Colombier 	"trap: TLB execute-inhibit",
56f43f8ee6SDavid du Colombier 	"trap: undefined 21",
57f43f8ee6SDavid du Colombier 	"trap: undefined 22",
58f43f8ee6SDavid du Colombier 	"trap: WATCH exception",
59f43f8ee6SDavid du Colombier 	"trap: machine checkcore",
60f43f8ee6SDavid du Colombier 	"trap: undefined 25",
61f43f8ee6SDavid du Colombier 	"trap: undefined 26",
62f43f8ee6SDavid du Colombier 	"trap: undefined 27",
63f43f8ee6SDavid du Colombier 	"trap: undefined 28",
64f43f8ee6SDavid du Colombier 	"trap: undefined 29",
65f43f8ee6SDavid du Colombier 	"trap: cache error",
66f43f8ee6SDavid du Colombier 	"trap: VCE (data)",
67f43f8ee6SDavid du Colombier };
68f43f8ee6SDavid du Colombier 
69f43f8ee6SDavid du Colombier char *fpcause[] =
70f43f8ee6SDavid du Colombier {
71f43f8ee6SDavid du Colombier 	"inexact operation",
72f43f8ee6SDavid du Colombier 	"underflow",
73f43f8ee6SDavid du Colombier 	"overflow",
74f43f8ee6SDavid du Colombier 	"division by zero",
75f43f8ee6SDavid du Colombier 	"invalid operation",
76f43f8ee6SDavid du Colombier };
77f43f8ee6SDavid du Colombier char	*fpexcname(Ureg*, ulong, char*, uint);
78f43f8ee6SDavid du Colombier #define FPEXPMASK	(0x3f<<12)	/* Floating exception bits in fcr31 */
79f43f8ee6SDavid du Colombier 
80f43f8ee6SDavid du Colombier struct {
81f43f8ee6SDavid du Colombier 	char	*name;
82f43f8ee6SDavid du Colombier 	uint	off;
83f43f8ee6SDavid du Colombier } regname[] = {
84f43f8ee6SDavid du Colombier 	"STATUS", Ureg_status,
85f43f8ee6SDavid du Colombier 	"PC",	Ureg_pc,
86f43f8ee6SDavid du Colombier 	"SP",	Ureg_sp,
87f43f8ee6SDavid du Colombier 	"CAUSE",Ureg_cause,
88f43f8ee6SDavid du Colombier 	"BADADDR", Ureg_badvaddr,
89f43f8ee6SDavid du Colombier 	"TLBVIRT", Ureg_tlbvirt,
90f43f8ee6SDavid du Colombier 	"HI",	Ureg_hi,
91f43f8ee6SDavid du Colombier 	"LO",	Ureg_lo,
92f43f8ee6SDavid du Colombier 	"R31",	Ureg_r31,
93f43f8ee6SDavid du Colombier 	"R30",	Ureg_r30,
94f43f8ee6SDavid du Colombier 	"R28",	Ureg_r28,
95f43f8ee6SDavid du Colombier 	"R27",	Ureg_r27,
96f43f8ee6SDavid du Colombier 	"R26",	Ureg_r26,
97f43f8ee6SDavid du Colombier 	"R25",	Ureg_r25,
98f43f8ee6SDavid du Colombier 	"R24",	Ureg_r24,
99f43f8ee6SDavid du Colombier 	"R23",	Ureg_r23,
100f43f8ee6SDavid du Colombier 	"R22",	Ureg_r22,
101f43f8ee6SDavid du Colombier 	"R21",	Ureg_r21,
102f43f8ee6SDavid du Colombier 	"R20",	Ureg_r20,
103f43f8ee6SDavid du Colombier 	"R19",	Ureg_r19,
104f43f8ee6SDavid du Colombier 	"R18",	Ureg_r18,
105f43f8ee6SDavid du Colombier 	"R17",	Ureg_r17,
106f43f8ee6SDavid du Colombier 	"R16",	Ureg_r16,
107f43f8ee6SDavid du Colombier 	"R15",	Ureg_r15,
108f43f8ee6SDavid du Colombier 	"R14",	Ureg_r14,
109f43f8ee6SDavid du Colombier 	"R13",	Ureg_r13,
110f43f8ee6SDavid du Colombier 	"R12",	Ureg_r12,
111f43f8ee6SDavid du Colombier 	"R11",	Ureg_r11,
112f43f8ee6SDavid du Colombier 	"R10",	Ureg_r10,
113f43f8ee6SDavid du Colombier 	"R9",	Ureg_r9,
114f43f8ee6SDavid du Colombier 	"R8",	Ureg_r8,
115f43f8ee6SDavid du Colombier 	"R7",	Ureg_r7,
116f43f8ee6SDavid du Colombier 	"R6",	Ureg_r6,
117f43f8ee6SDavid du Colombier 	"R5",	Ureg_r5,
118f43f8ee6SDavid du Colombier 	"R4",	Ureg_r4,
119f43f8ee6SDavid du Colombier 	"R3",	Ureg_r3,
120f43f8ee6SDavid du Colombier 	"R2",	Ureg_r2,
121f43f8ee6SDavid du Colombier 	"R1",	Ureg_r1,
122f43f8ee6SDavid du Colombier };
123f43f8ee6SDavid du Colombier 
124f43f8ee6SDavid du Colombier static Lock intrlock;
125f43f8ee6SDavid du Colombier static Handler handlers[ILmax+1];
126f43f8ee6SDavid du Colombier 
127f43f8ee6SDavid du Colombier static char *
ptlb(ulong phys)128f43f8ee6SDavid du Colombier ptlb(ulong phys)
129f43f8ee6SDavid du Colombier {
130f43f8ee6SDavid du Colombier 	static char buf[4][32];
131f43f8ee6SDavid du Colombier 	static int k;
132f43f8ee6SDavid du Colombier 	char *p;
133f43f8ee6SDavid du Colombier 
134f43f8ee6SDavid du Colombier 	k = (k+1)&3;
135f43f8ee6SDavid du Colombier 	p = buf[k];
136f43f8ee6SDavid du Colombier 	p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ",
137f43f8ee6SDavid du Colombier 		(phys<<6) & ~(BY2PG-1), (phys>>3)&7);
138f43f8ee6SDavid du Colombier 	if(phys & 4)
139f43f8ee6SDavid du Colombier 		*p++ = 'd';
140f43f8ee6SDavid du Colombier 	if(phys & 2)
141f43f8ee6SDavid du Colombier 		*p++ = 'v';
142f43f8ee6SDavid du Colombier 	if(phys & 1)
143f43f8ee6SDavid du Colombier 		*p++ = 'g';
144f43f8ee6SDavid du Colombier 	*p++ = ')';
145f43f8ee6SDavid du Colombier 	*p = 0;
146f43f8ee6SDavid du Colombier 	return buf[k];
147f43f8ee6SDavid du Colombier }
148f43f8ee6SDavid du Colombier 
149f43f8ee6SDavid du Colombier static void
kpteprint(Ureg * ur)150f43f8ee6SDavid du Colombier kpteprint(Ureg *ur)
151f43f8ee6SDavid du Colombier {
152f43f8ee6SDavid du Colombier 	ulong i, tlbstuff[3];
153f43f8ee6SDavid du Colombier 	KMap *k;
154f43f8ee6SDavid du Colombier 
155f43f8ee6SDavid du Colombier 	i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());
156f43f8ee6SDavid du Colombier 	print("tlbvirt=%#lux\n", i);
157f43f8ee6SDavid du Colombier 	i = gettlbp(i, tlbstuff);
158f43f8ee6SDavid du Colombier 	print("i=%lud v=%#lux p0=%s p1=%s\n",
159f43f8ee6SDavid du Colombier 		i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2]));
160f43f8ee6SDavid du Colombier 
161f43f8ee6SDavid du Colombier 	i = (ur->badvaddr & ~KMAPADDR)>>15;
162f43f8ee6SDavid du Colombier 	if(i > KPTESIZE){
163f43f8ee6SDavid du Colombier 		print("kpte index = %lud ?\n", i);
164f43f8ee6SDavid du Colombier 		return;
165f43f8ee6SDavid du Colombier 	}
166f43f8ee6SDavid du Colombier 	k = &kpte[i];
167f43f8ee6SDavid du Colombier 	print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n",
168f43f8ee6SDavid du Colombier 		i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);
169f43f8ee6SDavid du Colombier 	print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);
170f43f8ee6SDavid du Colombier }
171f43f8ee6SDavid du Colombier 
172f43f8ee6SDavid du Colombier void
kvce(Ureg * ur,int ecode)173f43f8ee6SDavid du Colombier kvce(Ureg *ur, int ecode)
174f43f8ee6SDavid du Colombier {
175f43f8ee6SDavid du Colombier 	char c;
176f43f8ee6SDavid du Colombier 	Pte **p;
177f43f8ee6SDavid du Colombier 	Page **pg;
178f43f8ee6SDavid du Colombier 	Segment *s;
179f43f8ee6SDavid du Colombier 	ulong addr, soff;
180f43f8ee6SDavid du Colombier 
181f43f8ee6SDavid du Colombier 	c = 'D';
182f43f8ee6SDavid du Colombier 	if(ecode == CVCEI)
183f43f8ee6SDavid du Colombier 		c = 'I';
184f43f8ee6SDavid du Colombier 	print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
185f43f8ee6SDavid du Colombier 	if((ur->badvaddr & KSEGM) == KSEG3) {
186f43f8ee6SDavid du Colombier 		kpteprint(ur);
187f43f8ee6SDavid du Colombier 		return;
188f43f8ee6SDavid du Colombier 	}
189f43f8ee6SDavid du Colombier 	if(up && !(ur->badvaddr & KSEGM)) {
190f43f8ee6SDavid du Colombier 		addr = ur->badvaddr;
191f43f8ee6SDavid du Colombier 		s = seg(up, addr, 0);
192f43f8ee6SDavid du Colombier 		if(s == 0){
193f43f8ee6SDavid du Colombier 			print("kvce: no seg for %#lux\n", addr);
194f43f8ee6SDavid du Colombier 			for(;;)
195f43f8ee6SDavid du Colombier 				;
196f43f8ee6SDavid du Colombier 		}
197f43f8ee6SDavid du Colombier 		addr &= ~(BY2PG-1);
198f43f8ee6SDavid du Colombier 		soff = addr - s->base;
199f43f8ee6SDavid du Colombier 		p = &s->map[soff/PTEMAPMEM];
200f43f8ee6SDavid du Colombier 		if(*p){
201f43f8ee6SDavid du Colombier 			pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
202f43f8ee6SDavid du Colombier 			if(*pg)
203f43f8ee6SDavid du Colombier 				print("kvce: pa=%#lux, va=%#lux\n",
204f43f8ee6SDavid du Colombier 					(*pg)->pa, (*pg)->va);
205f43f8ee6SDavid du Colombier 			else
206f43f8ee6SDavid du Colombier 				print("kvce: no *pg\n");
207f43f8ee6SDavid du Colombier 		}else
208f43f8ee6SDavid du Colombier 			print("kvce: no *p\n");
209f43f8ee6SDavid du Colombier 	}
210f43f8ee6SDavid du Colombier }
211f43f8ee6SDavid du Colombier 
212f43f8ee6SDavid du Colombier /* prepare to go to user space */
213f43f8ee6SDavid du Colombier void
kexit(Ureg *)214f43f8ee6SDavid du Colombier kexit(Ureg*)
215f43f8ee6SDavid du Colombier {
216f43f8ee6SDavid du Colombier 	Tos *tos;
217f43f8ee6SDavid du Colombier 
218f43f8ee6SDavid du Colombier 	/* precise time accounting, kernel exit */
219f43f8ee6SDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
220f43f8ee6SDavid du Colombier 	tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
221f43f8ee6SDavid du Colombier 	tos->pcycles = up->pcycles;
222f43f8ee6SDavid du Colombier 	tos->pid = up->pid;
223f43f8ee6SDavid du Colombier }
224f43f8ee6SDavid du Colombier 
225f43f8ee6SDavid du Colombier void
trap(Ureg * ur)226f43f8ee6SDavid du Colombier trap(Ureg *ur)
227f43f8ee6SDavid du Colombier {
228f43f8ee6SDavid du Colombier 	int ecode, clockintr, user, cop, x, fpchk;
229f43f8ee6SDavid du Colombier 	ulong fpfcr31;
230f43f8ee6SDavid du Colombier 	char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
231f43f8ee6SDavid du Colombier 	static int dumps;
232f43f8ee6SDavid du Colombier 
233f43f8ee6SDavid du Colombier 	ecode = (ur->cause>>2)&EXCMASK;
234f43f8ee6SDavid du Colombier 	user = ur->status&KUSER;
235f43f8ee6SDavid du Colombier 	if (ur->cause & TS)
236f43f8ee6SDavid du Colombier 		panic("trap: tlb shutdown");
237f43f8ee6SDavid du Colombier 
238f43f8ee6SDavid du Colombier 	fpchk = 0;
239f43f8ee6SDavid du Colombier 	if(user){
240f43f8ee6SDavid du Colombier 		up->dbgreg = ur;
241f43f8ee6SDavid du Colombier 		cycles(&up->kentry);
242f43f8ee6SDavid du Colombier 		/* no fpu, so no fp state to save */
243f43f8ee6SDavid du Colombier 	}
244f43f8ee6SDavid du Colombier 
245f43f8ee6SDavid du Colombier 	if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
246f43f8ee6SDavid du Colombier 		iprint("trap: proc %ld kernel stack getting full\n", up->pid);
247f43f8ee6SDavid du Colombier 		dumpregs(ur);
248f43f8ee6SDavid du Colombier 		dumpstack();
249f43f8ee6SDavid du Colombier 	}
250f43f8ee6SDavid du Colombier 	if (up == nil &&
251f43f8ee6SDavid du Colombier 	    (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
252f43f8ee6SDavid du Colombier 		iprint("trap: cpu%d kernel stack getting full\n", m->machno);
253f43f8ee6SDavid du Colombier 		dumpregs(ur);
254f43f8ee6SDavid du Colombier 		dumpstack();
255f43f8ee6SDavid du Colombier 	}
256f43f8ee6SDavid du Colombier 
257f43f8ee6SDavid du Colombier //	splhi();		/* for the experiment: make it explicit */
258f43f8ee6SDavid du Colombier 	/* clear EXL in status */
259f43f8ee6SDavid du Colombier 	setstatus(getstatus() & ~EXL);
260f43f8ee6SDavid du Colombier 
261f43f8ee6SDavid du Colombier 	clockintr = 0;
262f43f8ee6SDavid du Colombier 	switch(ecode){
263f43f8ee6SDavid du Colombier 	case CINT:
264f43f8ee6SDavid du Colombier 		clockintr = intr(ur);
265f43f8ee6SDavid du Colombier 		break;
266f43f8ee6SDavid du Colombier 
267f43f8ee6SDavid du Colombier 	case CFPE:
268f43f8ee6SDavid du Colombier 		panic("FP exception but no FPU");
269f43f8ee6SDavid du Colombier #ifdef OLD_MIPS_EXAMPLE
270f43f8ee6SDavid du Colombier 		fptrap(ur);
271f43f8ee6SDavid du Colombier 		clrfpintr();
272f43f8ee6SDavid du Colombier 		fpchk = 1;
273f43f8ee6SDavid du Colombier #endif
274f43f8ee6SDavid du Colombier 		break;
275f43f8ee6SDavid du Colombier 
276f43f8ee6SDavid du Colombier 	case CTLBM:
277f43f8ee6SDavid du Colombier 	case CTLBL:
278f43f8ee6SDavid du Colombier 	case CTLBS:
279f43f8ee6SDavid du Colombier 		/* user tlb entries assumed not overwritten during startup */
280f43f8ee6SDavid du Colombier 		if(up == 0)
281f43f8ee6SDavid du Colombier 			kernfault(ur, ecode);
282f43f8ee6SDavid du Colombier 
283f43f8ee6SDavid du Colombier 		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
284f43f8ee6SDavid du Colombier 			kfault(ur);
285f43f8ee6SDavid du Colombier 			break;
286f43f8ee6SDavid du Colombier 		}
287f43f8ee6SDavid du Colombier 		x = up->insyscall;
288f43f8ee6SDavid du Colombier 		up->insyscall = 1;
289f43f8ee6SDavid du Colombier 		spllo();
290f43f8ee6SDavid du Colombier 		faultmips(ur, user, ecode);
291f43f8ee6SDavid du Colombier 		up->insyscall = x;
292f43f8ee6SDavid du Colombier 		break;
293f43f8ee6SDavid du Colombier 
294f43f8ee6SDavid du Colombier 	case CVCEI:
295f43f8ee6SDavid du Colombier 	case CVCED:
296f43f8ee6SDavid du Colombier 		kvce(ur, ecode);
297f43f8ee6SDavid du Colombier 		goto Default;
298f43f8ee6SDavid du Colombier 
299f43f8ee6SDavid du Colombier 	case CWATCH:
300f43f8ee6SDavid du Colombier 		if(!user)
301f43f8ee6SDavid du Colombier 			panic("watchpoint trap from kernel mode pc=%#p",
302f43f8ee6SDavid du Colombier 				ur->pc);
303f43f8ee6SDavid du Colombier 		fpwatch(ur);
304f43f8ee6SDavid du Colombier 		break;
305f43f8ee6SDavid du Colombier 
306f43f8ee6SDavid du Colombier 	case CCPU:
307f43f8ee6SDavid du Colombier 		cop = (ur->cause>>28)&3;
308f43f8ee6SDavid du Colombier 		if(user && up && cop == 1) {
309f43f8ee6SDavid du Colombier 			if(up->fpstate & FPillegal) {
310f43f8ee6SDavid du Colombier 				/* someone used floating point in a note handler */
311f43f8ee6SDavid du Colombier 				postnote(up, 1,
312f43f8ee6SDavid du Colombier 					"sys: floating point in note handler",
313f43f8ee6SDavid du Colombier 					NDebug);
314f43f8ee6SDavid du Colombier 				break;
315f43f8ee6SDavid du Colombier 			}
316f43f8ee6SDavid du Colombier 			/* no fpu, so we can only emulate fp ins'ns */
317f43f8ee6SDavid du Colombier 			if (fpuemu(ur) < 0)
318f43f8ee6SDavid du Colombier 				postnote(up, 1,
319f43f8ee6SDavid du Colombier 					"sys: fp instruction not emulated",
320f43f8ee6SDavid du Colombier 					NDebug);
321f43f8ee6SDavid du Colombier 			else
322f43f8ee6SDavid du Colombier 				fpchk = 1;
323f43f8ee6SDavid du Colombier 			break;
324f43f8ee6SDavid du Colombier 		}
325f43f8ee6SDavid du Colombier 		/* Fallthrough */
326f43f8ee6SDavid du Colombier 
327f43f8ee6SDavid du Colombier 	Default:
328f43f8ee6SDavid du Colombier 	default:
329f43f8ee6SDavid du Colombier 		if(user) {
330f43f8ee6SDavid du Colombier 			spllo();
331f43f8ee6SDavid du Colombier 			snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
332f43f8ee6SDavid du Colombier 			postnote(up, 1, buf, NDebug);
333f43f8ee6SDavid du Colombier 			break;
334f43f8ee6SDavid du Colombier 		}
335f43f8ee6SDavid du Colombier 		if (ecode == CADREL || ecode == CADRES)
336f43f8ee6SDavid du Colombier 			iprint("kernel addr exception for va %#p pid %#ld %s\n",
337f43f8ee6SDavid du Colombier 				ur->badvaddr, (up? up->pid: 0),
338f43f8ee6SDavid du Colombier 				(up? up->text: ""));
339f43f8ee6SDavid du Colombier 		print("cpu%d: kernel %s pc=%#lux\n",
340f43f8ee6SDavid du Colombier 			m->machno, excname[ecode], ur->pc);
341f43f8ee6SDavid du Colombier 		dumpregs(ur);
342f43f8ee6SDavid du Colombier 		dumpstack();
343f43f8ee6SDavid du Colombier 		if(m->machno == 0)
344f43f8ee6SDavid du Colombier 			spllo();
345f43f8ee6SDavid du Colombier 		exit(1);
346f43f8ee6SDavid du Colombier 	}
347f43f8ee6SDavid du Colombier 
348f43f8ee6SDavid du Colombier 	if(fpchk) {
349f43f8ee6SDavid du Colombier 		fpfcr31 = up->fpsave.fpstatus;
350f43f8ee6SDavid du Colombier 		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
351f43f8ee6SDavid du Colombier 			spllo();
352f43f8ee6SDavid du Colombier 			fpexcep	= fpexcname(ur, fpfcr31, buf1, sizeof buf1);
353f43f8ee6SDavid du Colombier 			snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
354f43f8ee6SDavid du Colombier 			postnote(up, 1, buf, NDebug);
355f43f8ee6SDavid du Colombier 		}
356f43f8ee6SDavid du Colombier 	}
357f43f8ee6SDavid du Colombier 
358f43f8ee6SDavid du Colombier 	splhi();
359f43f8ee6SDavid du Colombier 
360f43f8ee6SDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
361f43f8ee6SDavid du Colombier 	if(up && up->delaysched && clockintr){
362f43f8ee6SDavid du Colombier 		sched();
363f43f8ee6SDavid du Colombier 		splhi();
364f43f8ee6SDavid du Colombier 	}
365f43f8ee6SDavid du Colombier 
366f43f8ee6SDavid du Colombier 	if(user){
367f43f8ee6SDavid du Colombier 		notify(ur);
368f43f8ee6SDavid du Colombier 		/* no fpu, so no fp state to restore */
369f43f8ee6SDavid du Colombier 		kexit(ur);
370f43f8ee6SDavid du Colombier 	}
371f43f8ee6SDavid du Colombier 
372f43f8ee6SDavid du Colombier 	/* restore EXL in status */
373f43f8ee6SDavid du Colombier 	setstatus(getstatus() | EXL);
374f43f8ee6SDavid du Colombier }
375f43f8ee6SDavid du Colombier 
376f43f8ee6SDavid du Colombier /* periodically zero all the interrupt counts */
377f43f8ee6SDavid du Colombier static void
resetcounts(void)378f43f8ee6SDavid du Colombier resetcounts(void)
379f43f8ee6SDavid du Colombier {
380f43f8ee6SDavid du Colombier 	int i;
381f43f8ee6SDavid du Colombier 	Handler *hp;
382f43f8ee6SDavid du Colombier 
383f43f8ee6SDavid du Colombier 	ilock(&intrlock);
384f43f8ee6SDavid du Colombier 	for (i = 0; i < nelem(handlers); i++)
385f43f8ee6SDavid du Colombier 		for (hp = &handlers[i]; hp != nil; hp = hp->next)
386f43f8ee6SDavid du Colombier 			hp->intrs = 0;
387f43f8ee6SDavid du Colombier 	iunlock(&intrlock);
388f43f8ee6SDavid du Colombier }
389f43f8ee6SDavid du Colombier 
390f43f8ee6SDavid du Colombier /*
391f43f8ee6SDavid du Colombier  *  set handlers
392f43f8ee6SDavid du Colombier  */
393f43f8ee6SDavid du Colombier void
intrenable(int irq,void (* h)(void *),void * arg)394f43f8ee6SDavid du Colombier intrenable(int irq, void (*h)(void *), void *arg)
395f43f8ee6SDavid du Colombier {
396f43f8ee6SDavid du Colombier 	Handler *hp;
397f43f8ee6SDavid du Colombier 	static int resetclock;
398f43f8ee6SDavid du Colombier 
399f43f8ee6SDavid du Colombier 	if (h == nil)
400f43f8ee6SDavid du Colombier 		panic("intrenable: nil handler intr %d", irq);
401f43f8ee6SDavid du Colombier 	if(irq < ILmin || irq >= nelem(handlers))
402f43f8ee6SDavid du Colombier 		panic("intrenable: bad handler intr %d %#p", irq, h);
403f43f8ee6SDavid du Colombier 
404f43f8ee6SDavid du Colombier 	hp = &handlers[irq];
405f43f8ee6SDavid du Colombier 	ilock(&intrlock);
406f43f8ee6SDavid du Colombier 	if (hp->handler != nil) {		/* occupied? */
407f43f8ee6SDavid du Colombier 		/* add a new one at the end of the chain */
408f43f8ee6SDavid du Colombier 		for (; hp->next != nil; hp = hp->next)
409f43f8ee6SDavid du Colombier 			;
410f43f8ee6SDavid du Colombier 		hp->next = smalloc(sizeof *hp);
411f43f8ee6SDavid du Colombier 		hp = hp->next;
412f43f8ee6SDavid du Colombier 		hp->next = nil;
413f43f8ee6SDavid du Colombier 	}
414f43f8ee6SDavid du Colombier 	hp->handler = h;
415f43f8ee6SDavid du Colombier 	hp->arg = arg;
416f43f8ee6SDavid du Colombier 	iunlock(&intrlock);
417f43f8ee6SDavid du Colombier 
418f43f8ee6SDavid du Colombier 	if (irq == ILduart0) {		/* special apb sub-interrupt */
419f43f8ee6SDavid du Colombier 		*Apbintrsts = 0;
420f43f8ee6SDavid du Colombier 		*Apbintrmask = 1 << Apbintruart;  /* enable, actually */
421f43f8ee6SDavid du Colombier 		coherence();
422f43f8ee6SDavid du Colombier 	}
423f43f8ee6SDavid du Colombier 	intron(1 << (ILshift + irq));
424f43f8ee6SDavid du Colombier 	if (!resetclock) {
425f43f8ee6SDavid du Colombier 		resetclock = 1;
426f43f8ee6SDavid du Colombier 		addclock0link(resetcounts, 100);
427f43f8ee6SDavid du Colombier 	}
428f43f8ee6SDavid du Colombier }
429f43f8ee6SDavid du Colombier 
430f43f8ee6SDavid du Colombier void
intrshutdown(void)431f43f8ee6SDavid du Colombier intrshutdown(void)
432f43f8ee6SDavid du Colombier {
433f43f8ee6SDavid du Colombier 	introff(INTMASK);
434f43f8ee6SDavid du Colombier }
435f43f8ee6SDavid du Colombier 
436f43f8ee6SDavid du Colombier static void
jabberoff(Ureg * ur,int irq,ulong bit)437f43f8ee6SDavid du Colombier jabberoff(Ureg *ur, int irq, ulong bit)
438f43f8ee6SDavid du Colombier {
439f43f8ee6SDavid du Colombier 	introff(bit);			/* interrupt off now ... */
440f43f8ee6SDavid du Colombier 	if (ur)
441f43f8ee6SDavid du Colombier 		ur->status &= ~bit;	/* ... and upon return */
442f43f8ee6SDavid du Colombier 	offintrs |= bit;
443f43f8ee6SDavid du Colombier 	iprint("irq %d jabbering; shutting it down\n", irq);
444f43f8ee6SDavid du Colombier }
445f43f8ee6SDavid du Colombier 
446f43f8ee6SDavid du Colombier ulong
pollall(Ureg * ur,ulong cause)447f43f8ee6SDavid du Colombier pollall(Ureg *ur, ulong cause)			/* must be called splhi */
448f43f8ee6SDavid du Colombier {
449f43f8ee6SDavid du Colombier 	int i, intrs, sts;
450f43f8ee6SDavid du Colombier 	ulong bit;
451f43f8ee6SDavid du Colombier 	Handler *hp;
452f43f8ee6SDavid du Colombier 
453f43f8ee6SDavid du Colombier 	/* exclude clock and sw intrs */
454f43f8ee6SDavid du Colombier 	intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus();
455f43f8ee6SDavid du Colombier 	if(intrs == 0)
456f43f8ee6SDavid du Colombier 		return cause;
457f43f8ee6SDavid du Colombier 
458f43f8ee6SDavid du Colombier 	ilock(&intrlock);
459f43f8ee6SDavid du Colombier 	for (i = ILmax; i >= ILmin; i--) {
460f43f8ee6SDavid du Colombier 		bit = 1 << (ILshift + i);
461f43f8ee6SDavid du Colombier 		if (!(intrs & bit))
462f43f8ee6SDavid du Colombier 			continue;
463f43f8ee6SDavid du Colombier 		intrcauses[i]++;
464f43f8ee6SDavid du Colombier 		for (hp = &handlers[i]; hp != nil; hp = hp->next)
465f43f8ee6SDavid du Colombier 			if (hp->handler) {
466f43f8ee6SDavid du Colombier 				if (i == ILduart0) {
467f43f8ee6SDavid du Colombier 					sts = *Apbintrsts;
468f43f8ee6SDavid du Colombier 					if((sts & (1 << Apbintruart)) == 0)
469f43f8ee6SDavid du Colombier 						continue;
470f43f8ee6SDavid du Colombier 					/* don't need to ack apb sub-intr */
471f43f8ee6SDavid du Colombier 					// *Apbintrsts &= ~(1 << Apbintruart);
472f43f8ee6SDavid du Colombier 				}
473f43f8ee6SDavid du Colombier 				(*hp->handler)(hp->arg);
474f43f8ee6SDavid du Colombier 				splhi();
475f43f8ee6SDavid du Colombier 				if (++hp->intrs > 25000) {
476f43f8ee6SDavid du Colombier 					jabberoff(ur, i, bit);
477f43f8ee6SDavid du Colombier 					intrs &= ~bit;
478f43f8ee6SDavid du Colombier 					hp->intrs = 0;
479f43f8ee6SDavid du Colombier 				}
480f43f8ee6SDavid du Colombier 			} else if (ur)
481f43f8ee6SDavid du Colombier 				iprint("no handler for interrupt %d\n", i);
482f43f8ee6SDavid du Colombier 		cause &= ~bit;
483f43f8ee6SDavid du Colombier 	}
484f43f8ee6SDavid du Colombier 	iunlock(&intrlock);
485f43f8ee6SDavid du Colombier 	return cause;
486f43f8ee6SDavid du Colombier }
487f43f8ee6SDavid du Colombier 
488f43f8ee6SDavid du Colombier int
intr(Ureg * ur)489f43f8ee6SDavid du Colombier intr(Ureg *ur)
490f43f8ee6SDavid du Colombier {
491f43f8ee6SDavid du Colombier 	int clockintr;
492f43f8ee6SDavid du Colombier 	ulong cause;
493f43f8ee6SDavid du Colombier 
494f43f8ee6SDavid du Colombier 	m->intr++;
495f43f8ee6SDavid du Colombier 	clockintr = 0;
496f43f8ee6SDavid du Colombier 	/*
497f43f8ee6SDavid du Colombier 	 * ignore interrupts that we have disabled, even if their cause bits
498f43f8ee6SDavid du Colombier 	 * are set.
499f43f8ee6SDavid du Colombier 	 */
500f43f8ee6SDavid du Colombier 	cause = ur->cause & ur->status & INTMASK;
501f43f8ee6SDavid du Colombier 	cause &= ~(INTR1|INTR0);		/* ignore sw interrupts */
502f43f8ee6SDavid du Colombier 	if (cause == 0)
503f43f8ee6SDavid du Colombier 		print("spurious interrupt\n");
504f43f8ee6SDavid du Colombier 	if(cause & INTR7){
505f43f8ee6SDavid du Colombier 		clock(ur);
506f43f8ee6SDavid du Colombier 		intrcauses[ILclock]++;
507f43f8ee6SDavid du Colombier 		cause &= ~(1 << (ILclock + ILshift));
508f43f8ee6SDavid du Colombier 		clockintr = 1;
509f43f8ee6SDavid du Colombier 	}
510f43f8ee6SDavid du Colombier 	cause = pollall(ur, cause);
511f43f8ee6SDavid du Colombier 	if(cause){
512f43f8ee6SDavid du Colombier 		print("intr: cause %#lux not handled\n", cause);
513f43f8ee6SDavid du Colombier 		exit(1);
514f43f8ee6SDavid du Colombier 	}
515f43f8ee6SDavid du Colombier 
516f43f8ee6SDavid du Colombier 	/* preemptive scheduling */
517f43f8ee6SDavid du Colombier 	if(up && !clockintr)
518f43f8ee6SDavid du Colombier 		preempted();
519f43f8ee6SDavid du Colombier 	/* if it was a clockintr, sched will be called at end of trap() */
520f43f8ee6SDavid du Colombier 	return clockintr;
521f43f8ee6SDavid du Colombier }
522f43f8ee6SDavid du Colombier 
523f43f8ee6SDavid du Colombier char*
fpexcname(Ureg * ur,ulong fcr31,char * buf,uint size)524f43f8ee6SDavid du Colombier fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
525f43f8ee6SDavid du Colombier {
526f43f8ee6SDavid du Colombier 	int i;
527f43f8ee6SDavid du Colombier 	char *s;
528f43f8ee6SDavid du Colombier 	ulong fppc;
529f43f8ee6SDavid du Colombier 
530f43f8ee6SDavid du Colombier 	fppc = ur->pc;
531f43f8ee6SDavid du Colombier 	if(ur->cause & BD)	/* branch delay */
532f43f8ee6SDavid du Colombier 		fppc += 4;
533f43f8ee6SDavid du Colombier 	s = 0;
534f43f8ee6SDavid du Colombier 	if(fcr31 & (1<<17))
535f43f8ee6SDavid du Colombier 		s = "unimplemented operation";
536f43f8ee6SDavid du Colombier 	else{
537f43f8ee6SDavid du Colombier 		fcr31 >>= 7;		/* trap enable bits */
538f43f8ee6SDavid du Colombier 		fcr31 &= (fcr31>>5);	/* anded with exceptions */
539f43f8ee6SDavid du Colombier 		for(i=0; i<5; i++)
540f43f8ee6SDavid du Colombier 			if(fcr31 & (1<<i))
541f43f8ee6SDavid du Colombier 				s = fpcause[i];
542f43f8ee6SDavid du Colombier 	}
543f43f8ee6SDavid du Colombier 
544f43f8ee6SDavid du Colombier 	if(s == 0)
545f43f8ee6SDavid du Colombier 		return "no floating point exception";
546f43f8ee6SDavid du Colombier 
547f43f8ee6SDavid du Colombier 	snprint(buf, size, "%s fppc=%#lux", s, fppc);
548f43f8ee6SDavid du Colombier 	return buf;
549f43f8ee6SDavid du Colombier }
550f43f8ee6SDavid du Colombier 
551*dc100ed4SDavid du Colombier // #define KERNPC(x) (KTZERO <= (ulong)(x) && (ulong)(x) < (ulong)&etext)
552f43f8ee6SDavid du Colombier 
553f43f8ee6SDavid du Colombier void
kernfault(Ureg * ur,int code)554f43f8ee6SDavid du Colombier kernfault(Ureg *ur, int code)
555f43f8ee6SDavid du Colombier {
556f43f8ee6SDavid du Colombier 	print("panic: kfault %s badvaddr=%#lux", excname[code], ur->badvaddr);
557f43f8ee6SDavid du Colombier 	kpteprint(ur);
558f43f8ee6SDavid du Colombier 	print("u=%#p status=%#lux pc=%#lux sp=%#lux\n",
559f43f8ee6SDavid du Colombier 		up, ur->status, ur->pc, ur->sp);
560f43f8ee6SDavid du Colombier 	delay(500);
561f43f8ee6SDavid du Colombier 	panic("kfault");
562f43f8ee6SDavid du Colombier }
563f43f8ee6SDavid du Colombier 
564f43f8ee6SDavid du Colombier static void
getpcsp(ulong * pc,ulong * sp)565f43f8ee6SDavid du Colombier getpcsp(ulong *pc, ulong *sp)
566f43f8ee6SDavid du Colombier {
567f43f8ee6SDavid du Colombier 	*pc = getcallerpc(&pc);
568f43f8ee6SDavid du Colombier 	*sp = (ulong)&pc-4;
569f43f8ee6SDavid du Colombier }
570f43f8ee6SDavid du Colombier 
571f43f8ee6SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))572f43f8ee6SDavid du Colombier callwithureg(void (*fn)(Ureg*))
573f43f8ee6SDavid du Colombier {
574f43f8ee6SDavid du Colombier 	Ureg ureg;
575f43f8ee6SDavid du Colombier 
576f43f8ee6SDavid du Colombier 	memset(&ureg, 0, sizeof ureg);
577f43f8ee6SDavid du Colombier 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
578f43f8ee6SDavid du Colombier 	ureg.r31 = getcallerpc(&fn);
579f43f8ee6SDavid du Colombier 	fn(&ureg);
580f43f8ee6SDavid du Colombier }
581f43f8ee6SDavid du Colombier 
582f43f8ee6SDavid du Colombier static void
_dumpstack(Ureg * ureg)583f43f8ee6SDavid du Colombier _dumpstack(Ureg *ureg)
584f43f8ee6SDavid du Colombier {
585f43f8ee6SDavid du Colombier 	ulong l, v, top, i;
586f43f8ee6SDavid du Colombier 	extern ulong etext;
587f43f8ee6SDavid du Colombier 
588f43f8ee6SDavid du Colombier 	if(up == 0)
589f43f8ee6SDavid du Colombier 		return;
590f43f8ee6SDavid du Colombier 
591f43f8ee6SDavid du Colombier 	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
592f43f8ee6SDavid du Colombier 		ureg->pc, ureg->sp, ureg->r31);
593f43f8ee6SDavid du Colombier 	top = (ulong)up->kstack + KSTACK;
594f43f8ee6SDavid du Colombier 	i = 0;
595f43f8ee6SDavid du Colombier 	for(l=ureg->sp; l < top; l += BY2WD) {
596f43f8ee6SDavid du Colombier 		v = *(ulong*)l;
597f43f8ee6SDavid du Colombier 		if(KTZERO < v && v < (ulong)&etext) {
598f43f8ee6SDavid du Colombier 			print("%.8lux=%.8lux ", l, v);
599f43f8ee6SDavid du Colombier 			if((++i%4) == 0){
600f43f8ee6SDavid du Colombier 				print("\n");
601f43f8ee6SDavid du Colombier 				delay(200);
602f43f8ee6SDavid du Colombier 			}
603f43f8ee6SDavid du Colombier 		}
604f43f8ee6SDavid du Colombier 	}
605f43f8ee6SDavid du Colombier 	print("\n");
606f43f8ee6SDavid du Colombier }
607f43f8ee6SDavid du Colombier 
608f43f8ee6SDavid du Colombier void
dumpstack(void)609f43f8ee6SDavid du Colombier dumpstack(void)
610f43f8ee6SDavid du Colombier {
611f43f8ee6SDavid du Colombier 	callwithureg(_dumpstack);
612f43f8ee6SDavid du Colombier }
613f43f8ee6SDavid du Colombier 
614f43f8ee6SDavid du Colombier static ulong
R(Ureg * ur,int i)615f43f8ee6SDavid du Colombier R(Ureg *ur, int i)
616f43f8ee6SDavid du Colombier {
617f43f8ee6SDavid du Colombier 	uchar *s;
618f43f8ee6SDavid du Colombier 
619f43f8ee6SDavid du Colombier 	s = (uchar*)ur;
620f43f8ee6SDavid du Colombier 	return *(ulong*)(s + regname[i].off - Uoffset);
621f43f8ee6SDavid du Colombier }
622f43f8ee6SDavid du Colombier 
623f43f8ee6SDavid du Colombier void
dumpregs(Ureg * ur)624f43f8ee6SDavid du Colombier dumpregs(Ureg *ur)
625f43f8ee6SDavid du Colombier {
626f43f8ee6SDavid du Colombier 	int i;
627f43f8ee6SDavid du Colombier 
628f43f8ee6SDavid du Colombier 	if(up)
629f43f8ee6SDavid du Colombier 		print("registers for %s %lud\n", up->text, up->pid);
630f43f8ee6SDavid du Colombier 	else
631f43f8ee6SDavid du Colombier 		print("registers for kernel\n");
632f43f8ee6SDavid du Colombier 
633f43f8ee6SDavid du Colombier 	for(i = 0; i < nelem(regname); i += 2)
634f43f8ee6SDavid du Colombier 		print("%s\t%#.8lux\t%s\t%#.8lux\n",
635f43f8ee6SDavid du Colombier 			regname[i].name,   R(ur, i),
636f43f8ee6SDavid du Colombier 			regname[i+1].name, R(ur, i+1));
637f43f8ee6SDavid du Colombier }
638f43f8ee6SDavid du Colombier 
639f43f8ee6SDavid du Colombier int
notify(Ureg * ur)640f43f8ee6SDavid du Colombier notify(Ureg *ur)
641f43f8ee6SDavid du Colombier {
642f43f8ee6SDavid du Colombier 	int l, s;
643f43f8ee6SDavid du Colombier 	ulong sp;
644f43f8ee6SDavid du Colombier 	Note *n;
645f43f8ee6SDavid du Colombier 
646f43f8ee6SDavid du Colombier 	if(up->procctl)
647f43f8ee6SDavid du Colombier 		procctl(up);
648f43f8ee6SDavid du Colombier 	if(up->nnote == 0)
649f43f8ee6SDavid du Colombier 		return 0;
650f43f8ee6SDavid du Colombier 
651f43f8ee6SDavid du Colombier 	s = spllo();
652f43f8ee6SDavid du Colombier 	qlock(&up->debug);
653f43f8ee6SDavid du Colombier 	up->fpstate |= FPillegal;
654f43f8ee6SDavid du Colombier 	up->notepending = 0;
655f43f8ee6SDavid du Colombier 	n = &up->note[0];
656f43f8ee6SDavid du Colombier 	if(strncmp(n->msg, "sys:", 4) == 0) {
657f43f8ee6SDavid du Colombier 		l = strlen(n->msg);
658f43f8ee6SDavid du Colombier 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
659f43f8ee6SDavid du Colombier 			l = ERRMAX-15;
660f43f8ee6SDavid du Colombier 
661f43f8ee6SDavid du Colombier 		seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
662f43f8ee6SDavid du Colombier 	}
663f43f8ee6SDavid du Colombier 
664f43f8ee6SDavid du Colombier 	if(n->flag != NUser && (up->notified || up->notify==0)) {
665f43f8ee6SDavid du Colombier 		if(n->flag == NDebug)
666f43f8ee6SDavid du Colombier 			pprint("suicide: %s\n", n->msg);
667f43f8ee6SDavid du Colombier 
668f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
669f43f8ee6SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
670f43f8ee6SDavid du Colombier 	}
671f43f8ee6SDavid du Colombier 
672f43f8ee6SDavid du Colombier 	if(up->notified) {
673f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
674f43f8ee6SDavid du Colombier 		splx(s);
675f43f8ee6SDavid du Colombier 		return 0;
676f43f8ee6SDavid du Colombier 	}
677f43f8ee6SDavid du Colombier 
678f43f8ee6SDavid du Colombier 	if(!up->notify) {
679f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
680f43f8ee6SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
681f43f8ee6SDavid du Colombier 	}
682f43f8ee6SDavid du Colombier 	sp = ur->usp & ~(BY2V-1);
683f43f8ee6SDavid du Colombier 	sp -= sizeof(Ureg);
684f43f8ee6SDavid du Colombier 
685f43f8ee6SDavid du Colombier 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
686f43f8ee6SDavid du Colombier 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
687f43f8ee6SDavid du Colombier 		pprint("suicide: bad address or sp in notify\n");
688f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
689f43f8ee6SDavid du Colombier 		pexit("Suicide", 0);
690f43f8ee6SDavid du Colombier 	}
691f43f8ee6SDavid du Colombier 
692f43f8ee6SDavid du Colombier 	memmove((Ureg*)sp, ur, sizeof(Ureg));	/* push user regs */
693f43f8ee6SDavid du Colombier 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
694f43f8ee6SDavid du Colombier 	up->ureg = (void*)sp;
695f43f8ee6SDavid du Colombier 
696f43f8ee6SDavid du Colombier 	sp -= BY2WD+ERRMAX;
697f43f8ee6SDavid du Colombier 	memmove((char*)sp, up->note[0].msg, ERRMAX);	/* push err string */
698f43f8ee6SDavid du Colombier 
699f43f8ee6SDavid du Colombier 	sp -= 3*BY2WD;
700f43f8ee6SDavid du Colombier 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
701f43f8ee6SDavid du Colombier 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
702f43f8ee6SDavid du Colombier 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
703f43f8ee6SDavid du Colombier 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
704f43f8ee6SDavid du Colombier 	ur->usp = sp;
705f43f8ee6SDavid du Colombier 	/*
706f43f8ee6SDavid du Colombier 	 * arrange to resume at user's handler as if handler(ureg, errstr)
707f43f8ee6SDavid du Colombier 	 * were being called.
708f43f8ee6SDavid du Colombier 	 */
709f43f8ee6SDavid du Colombier 	ur->pc = (ulong)up->notify;
710f43f8ee6SDavid du Colombier 
711f43f8ee6SDavid du Colombier 	up->notified = 1;
712f43f8ee6SDavid du Colombier 	up->nnote--;
713f43f8ee6SDavid du Colombier 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
714f43f8ee6SDavid du Colombier 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
715f43f8ee6SDavid du Colombier 
716f43f8ee6SDavid du Colombier 	qunlock(&up->debug);
717f43f8ee6SDavid du Colombier 	splx(s);
718f43f8ee6SDavid du Colombier 	return 1;
719f43f8ee6SDavid du Colombier }
720f43f8ee6SDavid du Colombier 
721f43f8ee6SDavid du Colombier /*
722f43f8ee6SDavid du Colombier  * Check that status is OK to return from note.
723f43f8ee6SDavid du Colombier  */
724f43f8ee6SDavid du Colombier int
validstatus(ulong kstatus,ulong ustatus)725f43f8ee6SDavid du Colombier validstatus(ulong kstatus, ulong ustatus)
726f43f8ee6SDavid du Colombier {
727f43f8ee6SDavid du Colombier //	if((kstatus & (INTMASK|KX|SX|UX)) != (ustatus & (INTMASK|KX|SX|UX)))
728f43f8ee6SDavid du Colombier 	if((kstatus & INTMASK) != (ustatus & INTMASK))
729f43f8ee6SDavid du Colombier 		return 0;
730f43f8ee6SDavid du Colombier 	if((ustatus&(KSU|ERL|EXL|IE)) != (KUSER|EXL|IE))
731f43f8ee6SDavid du Colombier 		return 0;
732f43f8ee6SDavid du Colombier 	if(ustatus & (0xFFFF0000&~CU1))	/* no CU3, CU2, CU0, RP, FR, RE, DS */
733f43f8ee6SDavid du Colombier 		return 0;
734f43f8ee6SDavid du Colombier 	return 1;
735f43f8ee6SDavid du Colombier }
736f43f8ee6SDavid du Colombier 
737f43f8ee6SDavid du Colombier /*
738f43f8ee6SDavid du Colombier  * Return user to state before notify(); called from user's handler.
739f43f8ee6SDavid du Colombier  */
740f43f8ee6SDavid du Colombier void
noted(Ureg * kur,Ureg ** urp,ulong arg0)741f43f8ee6SDavid du Colombier noted(Ureg *kur, Ureg **urp, ulong arg0)
742f43f8ee6SDavid du Colombier {
743f43f8ee6SDavid du Colombier 	Ureg *nur;
744f43f8ee6SDavid du Colombier 	ulong oureg, sp;
745f43f8ee6SDavid du Colombier 
746f43f8ee6SDavid du Colombier 	qlock(&up->debug);
747f43f8ee6SDavid du Colombier 	if(arg0!=NRSTR && !up->notified) {
748f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
749f43f8ee6SDavid du Colombier 		pprint("call to noted() when not notified\n");
750f43f8ee6SDavid du Colombier 		pexit("Suicide", 0);
751f43f8ee6SDavid du Colombier 	}
752f43f8ee6SDavid du Colombier 	up->notified = 0;
753f43f8ee6SDavid du Colombier 
754f43f8ee6SDavid du Colombier 	up->fpstate &= ~FPillegal;
755f43f8ee6SDavid du Colombier 
756f43f8ee6SDavid du Colombier 	nur = up->ureg;
757f43f8ee6SDavid du Colombier 
758f43f8ee6SDavid du Colombier 	oureg = (ulong)nur;
759f43f8ee6SDavid du Colombier 	if((oureg & (BY2WD-1))
760f43f8ee6SDavid du Colombier 	|| !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
761f43f8ee6SDavid du Colombier 		pprint("bad up->ureg in noted or call to noted() when not notified\n");
762f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
763f43f8ee6SDavid du Colombier 		pexit("Suicide", 0);
764f43f8ee6SDavid du Colombier 	}
765f43f8ee6SDavid du Colombier 
766f43f8ee6SDavid du Colombier 	if(!validstatus(kur->status, nur->status)) {
767f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
768f43f8ee6SDavid du Colombier 		pprint("bad noted ureg status %#lux\n", nur->status);
769f43f8ee6SDavid du Colombier 		pexit("Suicide", 0);
770f43f8ee6SDavid du Colombier 	}
771f43f8ee6SDavid du Colombier 
772f43f8ee6SDavid du Colombier 	memmove(*urp, up->ureg, sizeof(Ureg));
773f43f8ee6SDavid du Colombier 	switch(arg0) {
774f43f8ee6SDavid du Colombier 	case NCONT:
775f43f8ee6SDavid du Colombier 	case NRSTR:				/* only used by APE */
776f43f8ee6SDavid du Colombier 		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
777f43f8ee6SDavid du Colombier 			pprint("suicide: trap in noted\n");
778f43f8ee6SDavid du Colombier 			qunlock(&up->debug);
779f43f8ee6SDavid du Colombier 			pexit("Suicide", 0);
780f43f8ee6SDavid du Colombier 		}
781f43f8ee6SDavid du Colombier 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
782f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
783f43f8ee6SDavid du Colombier 		splhi();
784f43f8ee6SDavid du Colombier 		/*
785f43f8ee6SDavid du Colombier 		 * the old challenge and carrera ports called rfnote here,
786f43f8ee6SDavid du Colombier 		 * but newer ports do not, and notes seem to work only
787f43f8ee6SDavid du Colombier 		 * without this call.
788f43f8ee6SDavid du Colombier 		 */
789f43f8ee6SDavid du Colombier 		// rfnote(urp);		/* return from note with SP=urp */
790f43f8ee6SDavid du Colombier 		break;
791f43f8ee6SDavid du Colombier 
792f43f8ee6SDavid du Colombier 	case NSAVE:				/* only used by APE */
793f43f8ee6SDavid du Colombier 		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
794f43f8ee6SDavid du Colombier 			pprint("suicide: trap in noted\n");
795f43f8ee6SDavid du Colombier 			qunlock(&up->debug);
796f43f8ee6SDavid du Colombier 			pexit("Suicide", 0);
797f43f8ee6SDavid du Colombier 		}
798f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
799f43f8ee6SDavid du Colombier 		sp = oureg-4*BY2WD-ERRMAX;
800f43f8ee6SDavid du Colombier 
801f43f8ee6SDavid du Colombier 		splhi();
802f43f8ee6SDavid du Colombier 		(*urp)->sp = sp;
803f43f8ee6SDavid du Colombier 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
804f43f8ee6SDavid du Colombier 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
805f43f8ee6SDavid du Colombier 		(*urp)->r1 = oureg;		/* arg 1 is ureg* */
806f43f8ee6SDavid du Colombier 
807f43f8ee6SDavid du Colombier 		// rfnote(urp);		/* return from note with SP=urp */
808f43f8ee6SDavid du Colombier 		break;
809f43f8ee6SDavid du Colombier 
810f43f8ee6SDavid du Colombier 	default:
811f43f8ee6SDavid du Colombier 		pprint("unknown noted arg %#lux\n", arg0);
812f43f8ee6SDavid du Colombier 		up->lastnote.flag = NDebug;
813f43f8ee6SDavid du Colombier 		/* fall through */
814f43f8ee6SDavid du Colombier 
815f43f8ee6SDavid du Colombier 	case NDFLT:
816f43f8ee6SDavid du Colombier 		if(up->lastnote.flag == NDebug)
817f43f8ee6SDavid du Colombier 			pprint("suicide: %s\n", up->lastnote.msg);
818f43f8ee6SDavid du Colombier 		qunlock(&up->debug);
819f43f8ee6SDavid du Colombier 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
820f43f8ee6SDavid du Colombier 	}
821f43f8ee6SDavid du Colombier }
822f43f8ee6SDavid du Colombier 
823f43f8ee6SDavid du Colombier #include "../port/systab.h"
824f43f8ee6SDavid du Colombier 
825f43f8ee6SDavid du Colombier static Ref goodsyscall;
826f43f8ee6SDavid du Colombier static Ref totalsyscall;
827f43f8ee6SDavid du Colombier 
828f43f8ee6SDavid du Colombier static void
sctracesetup(ulong scallnr,ulong sp,uintptr pc,vlong * startnsp)829f43f8ee6SDavid du Colombier sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
830f43f8ee6SDavid du Colombier {
831f43f8ee6SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
832f43f8ee6SDavid du Colombier 		/*
833f43f8ee6SDavid du Colombier 		 * Redundant validaddr.  Do we care?
834f43f8ee6SDavid du Colombier 		 * Tracing syscalls is not exactly a fast path...
835f43f8ee6SDavid du Colombier 		 * Beware, validaddr currently does a pexit rather
836f43f8ee6SDavid du Colombier 		 * than an error if there's a problem; that might
837f43f8ee6SDavid du Colombier 		 * change in the future.
838f43f8ee6SDavid du Colombier 		 */
839f43f8ee6SDavid du Colombier 		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
840f43f8ee6SDavid du Colombier 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
841f43f8ee6SDavid du Colombier 
842f43f8ee6SDavid du Colombier 		syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
843f43f8ee6SDavid du Colombier 		up->procctl = Proc_stopme;
844f43f8ee6SDavid du Colombier 		procctl(up);
845f43f8ee6SDavid du Colombier 		if(up->syscalltrace)
846f43f8ee6SDavid du Colombier 			free(up->syscalltrace);
847f43f8ee6SDavid du Colombier 		up->syscalltrace = nil;
848f43f8ee6SDavid du Colombier 		*startnsp = todget(nil);
849f43f8ee6SDavid du Colombier 	}
850f43f8ee6SDavid du Colombier }
851f43f8ee6SDavid du Colombier 
852f43f8ee6SDavid du Colombier static void
sctracefinish(ulong scallnr,ulong sp,int ret,vlong startns)853f43f8ee6SDavid du Colombier sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
854f43f8ee6SDavid du Colombier {
855f43f8ee6SDavid du Colombier 	int s;
856f43f8ee6SDavid du Colombier 
857f43f8ee6SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
858f43f8ee6SDavid du Colombier 		up->procctl = Proc_stopme;
859f43f8ee6SDavid du Colombier 		sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
860f43f8ee6SDavid du Colombier 			startns, todget(nil));
861f43f8ee6SDavid du Colombier 		s = splhi();
862f43f8ee6SDavid du Colombier 		procctl(up);
863f43f8ee6SDavid du Colombier 		splx(s);
864f43f8ee6SDavid du Colombier 		if(up->syscalltrace)
865f43f8ee6SDavid du Colombier 			free(up->syscalltrace);
866f43f8ee6SDavid du Colombier 		up->syscalltrace = nil;
867f43f8ee6SDavid du Colombier 	}
868f43f8ee6SDavid du Colombier }
869f43f8ee6SDavid du Colombier 
870f43f8ee6SDavid du Colombier /*
871f43f8ee6SDavid du Colombier  * called directly from assembler, not via trap()
872f43f8ee6SDavid du Colombier  */
873f43f8ee6SDavid du Colombier long
syscall(Ureg * aur)874f43f8ee6SDavid du Colombier syscall(Ureg *aur)
875f43f8ee6SDavid du Colombier {
876f43f8ee6SDavid du Colombier 	int i;
877f43f8ee6SDavid du Colombier 	volatile long ret;
878f43f8ee6SDavid du Colombier 	ulong sp, scallnr;
879f43f8ee6SDavid du Colombier 	vlong startns;
880f43f8ee6SDavid du Colombier 	char *e;
881f43f8ee6SDavid du Colombier 	Ureg *ur;
882f43f8ee6SDavid du Colombier 
883f43f8ee6SDavid du Colombier 	cycles(&up->kentry);
884f43f8ee6SDavid du Colombier 
885f43f8ee6SDavid du Colombier 	incref(&totalsyscall);
886f43f8ee6SDavid du Colombier 	m->syscall++;
887f43f8ee6SDavid du Colombier 	up->insyscall = 1;
888f43f8ee6SDavid du Colombier 	ur = aur;
889f43f8ee6SDavid du Colombier 	up->pc = ur->pc;
890f43f8ee6SDavid du Colombier 	up->dbgreg = aur;
891f43f8ee6SDavid du Colombier 	ur->cause = 16<<2;	/* for debugging: system call is undef 16 */
892f43f8ee6SDavid du Colombier 
893f43f8ee6SDavid du Colombier 	scallnr = ur->r1;
894f43f8ee6SDavid du Colombier 	up->scallnr = ur->r1;
895f43f8ee6SDavid du Colombier 	sp = ur->sp;
896f43f8ee6SDavid du Colombier 	sctracesetup(scallnr, sp, ur->pc, &startns);
897f43f8ee6SDavid du Colombier 
898f43f8ee6SDavid du Colombier 	/* clear EXL in status */
899f43f8ee6SDavid du Colombier 	setstatus(getstatus() & ~EXL);
900f43f8ee6SDavid du Colombier 
901f43f8ee6SDavid du Colombier 	/* no fpu, so no fp state to save */
902f43f8ee6SDavid du Colombier 	spllo();
903f43f8ee6SDavid du Colombier 
904f43f8ee6SDavid du Colombier 	up->nerrlab = 0;
905f43f8ee6SDavid du Colombier 	ret = -1;
906f43f8ee6SDavid du Colombier 	if(!waserror()) {
907f43f8ee6SDavid du Colombier 		if(scallnr >= nsyscall || systab[scallnr] == 0){
908f43f8ee6SDavid du Colombier 			pprint("bad sys call number %ld pc %#lux\n",
909f43f8ee6SDavid du Colombier 				scallnr, ur->pc);
910f43f8ee6SDavid du Colombier 			postnote(up, 1, "sys: bad sys call", NDebug);
911f43f8ee6SDavid du Colombier 			error(Ebadarg);
912f43f8ee6SDavid du Colombier 		}
913f43f8ee6SDavid du Colombier 
914f43f8ee6SDavid du Colombier 		if(sp & (BY2WD-1)){
915f43f8ee6SDavid du Colombier 			pprint("odd sp in sys call pc %#lux sp %#lux\n",
916f43f8ee6SDavid du Colombier 				ur->pc, ur->sp);
917f43f8ee6SDavid du Colombier 			postnote(up, 1, "sys: odd stack", NDebug);
918f43f8ee6SDavid du Colombier 			error(Ebadarg);
919f43f8ee6SDavid du Colombier 		}
920f43f8ee6SDavid du Colombier 
921f43f8ee6SDavid du Colombier 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
922f43f8ee6SDavid du Colombier 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
923f43f8ee6SDavid du Colombier 
924f43f8ee6SDavid du Colombier 		up->s = *((Sargs*)(sp+BY2WD));
925f43f8ee6SDavid du Colombier 		up->psstate = sysctab[scallnr];
926f43f8ee6SDavid du Colombier 
927f43f8ee6SDavid du Colombier 		ret = systab[scallnr](up->s.args);
928f43f8ee6SDavid du Colombier 		poperror();
929f43f8ee6SDavid du Colombier 	}else{
930f43f8ee6SDavid du Colombier 		/* failure: save the error buffer for errstr */
931f43f8ee6SDavid du Colombier 		e = up->syserrstr;
932f43f8ee6SDavid du Colombier 		up->syserrstr = up->errstr;
933f43f8ee6SDavid du Colombier 		up->errstr = e;
934f43f8ee6SDavid du Colombier 		if(0 && up->pid == 1)
935f43f8ee6SDavid du Colombier 			print("[%lud %s] syscall %lud: %s\n",
936f43f8ee6SDavid du Colombier 				up->pid, up->text, scallnr, up->errstr);
937f43f8ee6SDavid du Colombier 	}
938f43f8ee6SDavid du Colombier 	if(up->nerrlab){
939f43f8ee6SDavid du Colombier 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
940f43f8ee6SDavid du Colombier 		for(i = 0; i < NERR; i++)
941f43f8ee6SDavid du Colombier 			print("sp=%#lux pc=%#lux\n",
942f43f8ee6SDavid du Colombier 				up->errlab[i].sp, up->errlab[i].pc);
943f43f8ee6SDavid du Colombier 		panic("error stack");
944f43f8ee6SDavid du Colombier 	}
945f43f8ee6SDavid du Colombier 	sctracefinish(scallnr, sp, ret, startns);
946f43f8ee6SDavid du Colombier 
947f43f8ee6SDavid du Colombier 	ur->pc += 4;
948f43f8ee6SDavid du Colombier 	ur->r1 = ret;
949f43f8ee6SDavid du Colombier 
950f43f8ee6SDavid du Colombier 	up->psstate = 0;
951f43f8ee6SDavid du Colombier 	up->insyscall = 0;
952f43f8ee6SDavid du Colombier 
953f43f8ee6SDavid du Colombier 	if(scallnr == NOTED) {				/* ugly hack */
954f43f8ee6SDavid du Colombier 		noted(ur, &aur, *(ulong*)(sp+BY2WD));	/* may return */
955f43f8ee6SDavid du Colombier 		ret = ur->r1;
956f43f8ee6SDavid du Colombier 	}
957f43f8ee6SDavid du Colombier 	incref(&goodsyscall);
958f43f8ee6SDavid du Colombier 	splhi();
959f43f8ee6SDavid du Colombier 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
960f43f8ee6SDavid du Colombier 		ur->r1 = ret;			/* load up for noted() above */
961f43f8ee6SDavid du Colombier 		notify(ur);
962f43f8ee6SDavid du Colombier 	}
963f43f8ee6SDavid du Colombier 	/* if we delayed sched because we held a lock, sched now */
964f43f8ee6SDavid du Colombier 	if(up->delaysched)
965f43f8ee6SDavid du Colombier 		sched();
966f43f8ee6SDavid du Colombier 	kexit(ur);
967f43f8ee6SDavid du Colombier 
968f43f8ee6SDavid du Colombier 	/* restore EXL in status */
969f43f8ee6SDavid du Colombier 	setstatus(getstatus() | EXL);
970f43f8ee6SDavid du Colombier 
971f43f8ee6SDavid du Colombier 	return ret;
972f43f8ee6SDavid du Colombier }
973f43f8ee6SDavid du Colombier 
974f43f8ee6SDavid du Colombier void
forkchild(Proc * p,Ureg * ur)975f43f8ee6SDavid du Colombier forkchild(Proc *p, Ureg *ur)
976f43f8ee6SDavid du Colombier {
977f43f8ee6SDavid du Colombier 	Ureg *cur;
978f43f8ee6SDavid du Colombier 
979f43f8ee6SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
980f43f8ee6SDavid du Colombier 	p->sched.pc = (ulong)forkret;
981f43f8ee6SDavid du Colombier 
982f43f8ee6SDavid du Colombier 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
983f43f8ee6SDavid du Colombier 	memmove(cur, ur, sizeof(Ureg));
984f43f8ee6SDavid du Colombier 
985f43f8ee6SDavid du Colombier 	cur->pc += 4;
986f43f8ee6SDavid du Colombier 
987f43f8ee6SDavid du Colombier 	/* Things from bottom of syscall we never got to execute */
988f43f8ee6SDavid du Colombier 	p->psstate = 0;
989f43f8ee6SDavid du Colombier 	p->insyscall = 0;
990f43f8ee6SDavid du Colombier }
991f43f8ee6SDavid du Colombier 
992f43f8ee6SDavid du Colombier static
993f43f8ee6SDavid du Colombier void
linkproc(void)994f43f8ee6SDavid du Colombier linkproc(void)
995f43f8ee6SDavid du Colombier {
996f43f8ee6SDavid du Colombier 	spllo();
997f43f8ee6SDavid du Colombier 	up->kpfun(up->kparg);
998f43f8ee6SDavid du Colombier 	pexit("kproc exiting", 0);
999f43f8ee6SDavid du Colombier }
1000f43f8ee6SDavid du Colombier 
1001f43f8ee6SDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)1002f43f8ee6SDavid du Colombier kprocchild(Proc *p, void (*func)(void*), void *arg)
1003f43f8ee6SDavid du Colombier {
1004f43f8ee6SDavid du Colombier 	p->sched.pc = (ulong)linkproc;
1005f43f8ee6SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK;
1006f43f8ee6SDavid du Colombier 
1007f43f8ee6SDavid du Colombier 	p->kpfun = func;
1008f43f8ee6SDavid du Colombier 	p->kparg = arg;
1009f43f8ee6SDavid du Colombier }
1010f43f8ee6SDavid du Colombier 
1011f43f8ee6SDavid du Colombier /* set up user registers before return from exec() */
1012f43f8ee6SDavid du Colombier long
execregs(ulong entry,ulong ssize,ulong nargs)1013f43f8ee6SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
1014f43f8ee6SDavid du Colombier {
1015f43f8ee6SDavid du Colombier 	Ureg *ur;
1016f43f8ee6SDavid du Colombier 	ulong *sp;
1017f43f8ee6SDavid du Colombier 
1018f43f8ee6SDavid du Colombier 	sp = (ulong*)(USTKTOP - ssize);
1019f43f8ee6SDavid du Colombier 	*--sp = nargs;
1020f43f8ee6SDavid du Colombier 
1021f43f8ee6SDavid du Colombier 	ur = (Ureg*)up->dbgreg;
1022f43f8ee6SDavid du Colombier 	ur->usp = (ulong)sp;
1023f43f8ee6SDavid du Colombier 	ur->pc = entry - 4;		/* syscall advances it */
1024f43f8ee6SDavid du Colombier 	up->fpsave.fpstatus = initfp.fpstatus;
1025f43f8ee6SDavid du Colombier 	return USTKTOP-sizeof(Tos);	/* address of kernel/user shared data */
1026f43f8ee6SDavid du Colombier }
1027f43f8ee6SDavid du Colombier 
1028f43f8ee6SDavid du Colombier ulong
userpc(void)1029f43f8ee6SDavid du Colombier userpc(void)
1030f43f8ee6SDavid du Colombier {
1031f43f8ee6SDavid du Colombier 	Ureg *ur;
1032f43f8ee6SDavid du Colombier 
1033f43f8ee6SDavid du Colombier 	ur = (Ureg*)up->dbgreg;
1034f43f8ee6SDavid du Colombier 	return ur->pc;
1035f43f8ee6SDavid du Colombier }
1036f43f8ee6SDavid du Colombier 
1037f43f8ee6SDavid du Colombier /*
1038f43f8ee6SDavid du Colombier  * This routine must save the values of registers the user is not
1039f43f8ee6SDavid du Colombier  * permitted to write from devproc and then restore the saved values
1040f43f8ee6SDavid du Colombier  * before returning
1041f43f8ee6SDavid du Colombier  */
1042f43f8ee6SDavid du Colombier void
setregisters(Ureg * xp,char * pureg,char * uva,int n)1043f43f8ee6SDavid du Colombier setregisters(Ureg *xp, char *pureg, char *uva, int n)
1044f43f8ee6SDavid du Colombier {
1045f43f8ee6SDavid du Colombier 	ulong status;
1046f43f8ee6SDavid du Colombier 
1047f43f8ee6SDavid du Colombier 	status = xp->status;
1048f43f8ee6SDavid du Colombier 	memmove(pureg, uva, n);
1049f43f8ee6SDavid du Colombier 	xp->status = status;
1050f43f8ee6SDavid du Colombier }
1051f43f8ee6SDavid du Colombier 
1052f43f8ee6SDavid du Colombier /*
1053f43f8ee6SDavid du Colombier  * Give enough context in the ureg to produce a kernel stack for
1054f43f8ee6SDavid du Colombier  * a sleeping process
1055f43f8ee6SDavid du Colombier  */
1056f43f8ee6SDavid du Colombier void
setkernur(Ureg * xp,Proc * p)1057f43f8ee6SDavid du Colombier setkernur(Ureg *xp, Proc *p)
1058f43f8ee6SDavid du Colombier {
1059f43f8ee6SDavid du Colombier 	xp->pc = p->sched.pc;
1060f43f8ee6SDavid du Colombier 	xp->sp = p->sched.sp;
1061f43f8ee6SDavid du Colombier 	xp->r24 = (ulong)p;		/* up */
1062f43f8ee6SDavid du Colombier 	xp->r31 = (ulong)sched;
1063f43f8ee6SDavid du Colombier }
1064f43f8ee6SDavid du Colombier 
1065f43f8ee6SDavid du Colombier ulong
dbgpc(Proc * p)1066f43f8ee6SDavid du Colombier dbgpc(Proc *p)
1067f43f8ee6SDavid du Colombier {
1068f43f8ee6SDavid du Colombier 	Ureg *ur;
1069f43f8ee6SDavid du Colombier 
1070f43f8ee6SDavid du Colombier 	ur = p->dbgreg;
1071f43f8ee6SDavid du Colombier 	if(ur == 0)
1072f43f8ee6SDavid du Colombier 		return 0;
1073f43f8ee6SDavid du Colombier 
1074f43f8ee6SDavid du Colombier 	return ur->pc;
1075f43f8ee6SDavid du Colombier }
1076