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