vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

trap.c (22655B)


      1 /*
      2  * Heavily modified copy of /sys/src/9/pc/trap.c
      3  * A shell of its former self.
      4  */
      5 #define	WANT_M
      6 
      7 #include	"u.h"
      8 #include	"libvx32/vx32.h"
      9 #include	"tos.h"
     10 #include	"lib.h"
     11 #include	"mem.h"
     12 #include	"dat.h"
     13 #include	"fns.h"
     14 #include	"io.h"
     15 #include	"ureg.h"
     16 #include	"error.h"
     17 #include	"trace.h"
     18 #include	"systab.h"
     19 
     20 int tracesyscalls;
     21 static void noted(Ureg*, ulong);
     22 static void mathemu(Ureg*, void*);
     23 static void syscall(Ureg*);
     24 
     25 /* going to user space */
     26 void
     27 kexit(Ureg *ureg)
     28 {
     29 	uvlong t;
     30 	Tos *tos;
     31 
     32 	/* precise time accounting, kernel exit */
     33 	tos = (Tos*)(up->pmmu.uzero+USTKTOP-sizeof(Tos));
     34 	cycles(&t);
     35 	tos->kcycles += t - up->kentry;
     36 	tos->pcycles = up->pcycles;
     37 	tos->pid = up->pid;
     38 }
     39 
     40 static char* excname[32] = {
     41 	"divide error",
     42 	"debug exception",
     43 	"nonmaskable interrupt",
     44 	"breakpoint",
     45 	"overflow",
     46 	"bounds check",
     47 	"invalid opcode",
     48 	"coprocessor not available",
     49 	"double fault",
     50 	"coprocessor segment overrun",
     51 	"invalid TSS",
     52 	"segment not present",
     53 	"stack exception",
     54 	"general protection violation",
     55 	"page fault",
     56 	"15 (reserved)",
     57 	"coprocessor error",
     58 	"alignment check",
     59 	"machine check",
     60 	"19 (reserved)",
     61 	"20 (reserved)",
     62 	"21 (reserved)",
     63 	"22 (reserved)",
     64 	"23 (reserved)",
     65 	"24 (reserved)",
     66 	"25 (reserved)",
     67 	"26 (reserved)",
     68 	"27 (reserved)",
     69 	"28 (reserved)",
     70 	"29 (reserved)",
     71 	"30 (reserved)",
     72 	"31 (reserved)",
     73 };
     74 
     75 /*
     76  * Handle a trap.
     77  */
     78 void
     79 trap(Ureg *ureg)
     80 {
     81 	char buf[ERRMAX];
     82 	int vno;
     83 
     84 	vno = ureg->trap;
     85 
     86 	switch(vno){
     87 	case VXTRAP_FPOFF:
     88 		mathemu(ureg, nil);
     89 		return;
     90 	
     91 	case VXTRAP_SOFT+0x40:	/* int $0x40 - system call */
     92 		if(tracesyscalls){
     93 			uint32 *sp = (uint32*)(up->pmmu.uzero + ureg->usp);
     94 			iprint("%d [%s] %s %#ux %08ux %08ux %08ux %08ux\n",
     95 				up->pid, up->text,
     96 				sysctab[ureg->ax], sp[0], sp[1], sp[2], sp[3]);
     97 		}
     98 		syscall(ureg);
     99 		if(tracesyscalls){
    100 			if(ureg->ax == -1)
    101 				iprint("%d [%s] -> %s\n", up->pid, up->text, up->syserrstr);
    102 			else
    103 				iprint("%d [%s] -> %#ux\n", up->pid, up->text, ureg->ax);
    104 		}
    105 		return;
    106 	
    107 	case VXTRAP_IRQ+VXIRQ_TIMER:
    108 		sched();
    109 		break;
    110 	
    111 	case 3:	// breakpoint
    112 		/* restore pc to instruction that caused the trap */
    113 		ureg->pc--;
    114 		sprint(buf, "sys: breakpoint");
    115 		postnote(up, 1, buf, NDebug);
    116 		break;
    117 
    118 	default:
    119 		if(vno < nelem(excname)){
    120 			spllo();
    121 			sprint(buf, "sys: trap: %s", excname[vno]);
    122 			postnote(up, 1, buf, NDebug);
    123 		}else{
    124 			dumpregs(ureg);
    125 			if(vno < nelem(excname))
    126 				panic("%s", excname[vno]);
    127 			panic("unknown trap/intr: %#x", vno);
    128 		}
    129 		break;
    130 	}
    131 
    132 	if(up->procctl || up->nnote)
    133 		notify(ureg);
    134 	spllo();	/* no actual effect, just silences prints */
    135 	kexit(ureg);
    136 }
    137 
    138 void
    139 dumpregs2(Ureg* ureg)
    140 {
    141 	if(up)
    142 		print("cpu%d: registers for %s %lud\n",
    143 			m->machno, up->text, up->pid);
    144 	else
    145 		print("cpu%d: registers for kernel\n", m->machno);
    146 	print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
    147 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
    148 	print(" USP=%luX\n", ureg->usp);
    149 	print("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
    150 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
    151 	print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
    152 		ureg->si, ureg->di, ureg->bp);
    153 }
    154 
    155 void
    156 dumpregs(Ureg* ureg)
    157 {
    158 	dumpregs2(ureg);
    159 
    160 	/*
    161 	 * Processor control registers.
    162 	 * If machine check exception, time stamp counter, page size extensions
    163 	 * or enhanced virtual 8086 mode extensions are supported, there is a
    164 	 * CR4. If there is a CR4 and machine check extensions, read the machine
    165 	 * check address and machine check type registers if RDMSR supported.
    166 	print("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
    167 		getcr0(), getcr2(), getcr3());
    168 	if(m->cpuiddx & 0x9A){
    169 		vlong mca, mct;
    170 		iprint(" CR4 %8.8lux", getcr4());
    171 		if((m->cpuiddx & 0xA0) == 0xA0){
    172 			rdmsr(0x00, &mca);
    173 			rdmsr(0x01, &mct);
    174 			iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
    175 		}
    176 	}
    177 	print("\n  ur %lux up %lux\n", ureg, up);
    178 	 */
    179 }
    180 
    181 static void
    182 fmtrwdata(Fmt *f, ulong s, int n, char *suffix)
    183 {
    184 	char *t, *src;
    185 	int i;
    186 
    187 	if (! s) {
    188 		fmtprint(f, "0x0", suffix);
    189 		return;
    190 	}
    191 	src = uvalidaddr(s, 1, 0);
    192 	t = smalloc(n+1);
    193 	for(i = 0; i < n; i++)
    194 		if (isgraph(src[i]))
    195 			t[i] = src[i];
    196 		else
    197 			t[i] = '.';
    198 
    199 	fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
    200 	free(t);
    201 }
    202 
    203 static void
    204 fmtuserstring(Fmt *f, ulong s, char *suffix)
    205 {
    206 	char *es, *t, *src;
    207 	int n;
    208 
    209 	if (! s){
    210 		fmtprint(f, "0/\"\"%s", suffix);
    211 		return;
    212 	}
    213 	src = uvalidaddr(s, 1, 0);
    214 	es = vmemchr(src, 0, 1<<16);
    215 	n = es - src;
    216 	t = smalloc(n+1);
    217 	memmove(t, src, n);
    218 	t[n] = 0;
    219 	fmtprint(f, "%08ux/\"%s\"%s", s, t, suffix);
    220 	free(t);
    221 }
    222 
    223 static void
    224 syscallprint(Ureg *ureg)
    225 {
    226 	uint32 *sp;
    227 	int syscallno;
    228 	vlong offset;
    229 	Fmt fmt;
    230 	int len;
    231   	uint32 argp, a;
    232 
    233 	sp = (uint32*)(up->pmmu.uzero + ureg->usp);
    234 	syscallno = ureg->ax;
    235 	offset = 0;
    236 	fmtstrinit(&fmt);
    237 	fmtprint(&fmt, "%d %s ", up->pid, up->text);
    238 	/* accomodate process-private system calls */
    239 
    240 	if(syscallno > nelem(sysctab))
    241 		fmtprint(&fmt, " %d %#x ", syscallno, sp[0]);
    242 	else
    243 		fmtprint(&fmt, "%s %#ux ", sysctab[syscallno], sp[0]);
    244 
    245 	if(up->syscalltrace)
    246 		free(up->syscalltrace);
    247 
    248 	switch(syscallno) {
    249 	case SYSR1:
    250 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    251 		break;
    252 	case _ERRSTR:
    253 		fmtuserstring(&fmt, sp[1], "");
    254 		break;
    255 	case BIND:
    256 		fmtuserstring(&fmt, sp[1], " ");
    257 		fmtuserstring(&fmt, sp[2], " ");
    258 		fmtprint(&fmt, "%#ux",  sp[3]);
    259 		break;
    260 	case CHDIR:
    261 		fmtuserstring(&fmt, sp[1], "");
    262 		break;
    263 	case CLOSE:
    264 		fmtprint(&fmt, "%d", sp[1]);
    265 		break;
    266 	case DUP:
    267 		fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
    268 		break;
    269 	case ALARM:
    270 		fmtprint(&fmt, "%08ux ", sp[1]);
    271 		break;
    272 	case EXEC: 
    273 		fmtuserstring(&fmt, sp[1], "");
    274 		argp = sp[2];
    275 		for(;;argp += BY2WD) {
    276 			a = *(uint32*)uvalidaddr(argp, BY2WD, 0);
    277 			if(a == 0)
    278 				break;
    279 			fmtprint(&fmt, " ");
    280 			fmtuserstring(&fmt, a, "");
    281 		}
    282 		break;
    283 	case EXITS:
    284 		fmtuserstring(&fmt, sp[1], "");
    285 		break;
    286 	case _FSESSION:
    287 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    288 		break;
    289 	case FAUTH:
    290 		fmtprint(&fmt, "%08ux", sp[1]);
    291 		fmtuserstring(&fmt, sp[2], "");
    292 		break;
    293 	case _FSTAT:
    294 		fmtprint(&fmt, "%08ux %#ux %08ux", sp[1], sp[2], sp[3]);
    295 		break;
    296 	case SEGBRK:
    297 		fmtprint(&fmt, "%#ux %#ux", sp[1], sp[2]);
    298 		break;
    299 	case _MOUNT:
    300 		fmtprint(&fmt, "%d %d ", sp[1], sp[2]);
    301 		fmtuserstring(&fmt, sp[3], " ");
    302 		fmtprint(&fmt, "%08ux ", sp[4]);
    303 		fmtuserstring(&fmt, sp[5], "");
    304 		break;
    305 	case OPEN:
    306 		fmtuserstring(&fmt, sp[1], " ");
    307 		fmtprint(&fmt, "%08ux", sp[2]);
    308 		break;
    309 	case OSEEK:
    310 		fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
    311 		break;
    312 	case SLEEP: 
    313 		fmtprint(&fmt, "%d", sp[1]);
    314 		break;
    315 	case _STAT:
    316 		fmtuserstring(&fmt, sp[1], " ");
    317 		fmtprint(&fmt, "%#ux %d", sp[2], sp[3]);
    318 		break;
    319 	case RFORK:
    320 		fmtprint(&fmt, "%08ux", sp[1] );
    321 		break;
    322 	case PIPE: 
    323 		break;
    324 	case CREATE:
    325 		fmtuserstring(&fmt, sp[1], " ");
    326 		fmtprint(&fmt, "%08ux %08ux", sp[2], sp[3]);
    327 		break;
    328 	case FD2PATH:
    329 		fmtprint(&fmt, "%d ", sp[1]);
    330 		break;
    331 	case BRK_:
    332 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    333 		break;
    334 	case REMOVE:
    335 		fmtuserstring(&fmt, sp[1], " ");
    336 		break;
    337 	/* deprecated */
    338 	case _WSTAT:
    339 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    340 		break;
    341 	case _FWSTAT:
    342 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    343 		break;
    344 	case NOTIFY:
    345 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    346 		break;
    347 	case NOTED:
    348 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    349 		break;
    350 	case SEGATTACH:
    351 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    352 		break;
    353 	case SEGDETACH:
    354 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    355 		break;
    356 	case SEGFREE:
    357 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    358 		break;
    359 	case SEGFLUSH:
    360 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    361 		break;
    362 	case RENDEZVOUS:
    363 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    364 		break;
    365 	case UNMOUNT:
    366 		fmtuserstring(&fmt, sp[1], " ");
    367 		break;
    368 	case _WAIT:
    369 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    370 		break;
    371 	case SEMACQUIRE:
    372 		fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
    373 		break;
    374 	case SEMRELEASE:
    375 		fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
    376 		break;
    377 	case SEEK:
    378 		fmtprint(&fmt, "%08ux %016ux %08ux", sp[1], *(vlong *)&sp[2], sp[4]);
    379 		break;
    380 	case FVERSION:
    381 		fmtprint(&fmt, "%08ux %08ux ", sp[1], sp[2]);
    382 		fmtuserstring(&fmt, sp[5], "");
    383 		break;
    384 	case ERRSTR:
    385 		fmtprint(&fmt, "%#ux/", sp[1]);
    386 		break;
    387 	case WSTAT:
    388 	case STAT:
    389 		fmtprint(&fmt, "%08ux ", sp[1]);
    390 		fmtuserstring(&fmt, sp[2], " ");
    391 		fmtprint(&fmt, "%08ux", sp[3]);
    392 		break;
    393 	case FSTAT:
    394 	case FWSTAT:
    395 		fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
    396 		break;
    397 	case MOUNT:
    398 		fmtprint(&fmt, "%d %d ", sp[1], sp[3]);
    399 		fmtuserstring(&fmt, sp[3], " ");
    400 		fmtprint(&fmt, "%08ux", sp[4]);
    401 		fmtuserstring(&fmt, sp[5], "");
    402 		break;
    403 	case AWAIT:
    404 		break;
    405 	case _READ: 
    406 	case PREAD:
    407 		fmtprint(&fmt, "%d ", sp[1]);
    408 		break;
    409 	case _WRITE:
    410 		offset = -1;
    411 	case PWRITE:
    412 		fmtprint(&fmt, "%d ", sp[1]);
    413 		if (sp[3] < 64)
    414 			len = sp[3];
    415 		else
    416 			len = 64;
    417 		fmtrwdata(&fmt, sp[2], len, " ");
    418 		if(! offset)
    419 			offset = *(vlong *)&sp[4];
    420 		fmtprint(&fmt, "%d %#llx", sp[3], offset);
    421 		break;
    422 	}
    423 	up->syscalltrace = fmtstrflush(&fmt);
    424 }
    425 
    426 static void
    427 retprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop)
    428 {
    429 	int errstrlen, len;
    430 	vlong offset;
    431 	char *errstr;
    432 	Fmt fmt;
    433 
    434 	fmtstrinit(&fmt);
    435 	len = 0;
    436 	errstrlen = 0;
    437 	offset = 0;
    438 	if (ureg->ax != -1)
    439 		errstr = "";
    440 	else
    441 		errstr = up->syserrstr;
    442 
    443 	if(up->syscalltrace)
    444 		free(up->syscalltrace);
    445 
    446 	switch(syscallno) {
    447 	case SYSR1:
    448 	case BIND:
    449 	case CHDIR:
    450 	case CLOSE:
    451 	case DUP:
    452 	case ALARM:
    453 	case EXEC:
    454 	case EXITS:
    455 	case _FSESSION:
    456 	case FAUTH:
    457 	case _FSTAT:
    458 	case SEGBRK:
    459 	case _MOUNT:
    460 	case OPEN:
    461 	case OSEEK:
    462 	case SLEEP:
    463 	case _STAT:
    464 	case _WRITE:
    465 	case PIPE:
    466 	case CREATE:
    467 	case BRK_:
    468 	case REMOVE:
    469 	case _WSTAT:
    470 	case _FWSTAT:
    471 	case NOTIFY:
    472 	case NOTED:
    473 	case SEGATTACH:
    474 	case SEGDETACH:
    475 	case SEGFREE:
    476 	case SEGFLUSH:
    477 	case RENDEZVOUS:
    478 	case UNMOUNT:
    479 	case _WAIT:
    480 	case SEMACQUIRE:
    481 	case SEMRELEASE:
    482 	case SEEK:
    483 	case FVERSION:
    484 	case STAT:
    485 	case FSTAT:
    486 	case WSTAT:
    487 	case FWSTAT:
    488 	case MOUNT:
    489 	case PWRITE:
    490 	case RFORK:
    491 	default: 
    492 	break;
    493 	case AWAIT:
    494 		if(ureg->ax > 0){
    495 			fmtuserstring(&fmt, up->s.args[0], " ");
    496 			fmtprint(&fmt, "%d", up->s.args[1]);
    497 		} else {
    498 			fmtprint(&fmt, "%#ux/\"\" %d", up->s.args[0], up->s.args[1]);
    499 		}
    500 		break;
    501 	case _ERRSTR:
    502 		errstrlen = 64;
    503 	case ERRSTR:
    504 		if(! errstrlen)
    505 			errstrlen = up->s.args[1];
    506 		if(ureg->ax > 0){
    507 			fmtuserstring(&fmt, up->s.args[0], " ");
    508 			fmtprint(&fmt, "%d", errstrlen);
    509 		} else {
    510 			fmtprint(&fmt, "\"\" %d", errstrlen);
    511 		}
    512 		break;
    513 	case FD2PATH:
    514 		if(ureg->ax == -1)
    515 			fmtprint(&fmt, "\"\" %d", up->s.args[2]);
    516 		else {
    517 			fmtuserstring(&fmt, up->s.args[1], " ");
    518 			fmtprint(&fmt, "%d", errstrlen);
    519 		}
    520 		break;
    521 	case _READ:
    522 		offset = -1;
    523 	case PREAD:
    524 		if(ureg->ax == -1)
    525 			fmtprint(&fmt, "/\"\" %d 0x%ullx", up->s.args[2], *(vlong *)&up->s.args[3]);
    526 		else {
    527 			if (ureg->ax > 64)
    528 				len = 64;
    529 			else
    530 				len = ureg->ax;
    531 			fmtrwdata(&fmt, up->s.args[1], len, " ");
    532 			if(! offset)
    533 				offset = *(vlong *)&up->s.args[3];
    534 			fmtprint(&fmt, "%d %#llx", up->s.args[2], offset);
    535 		}
    536 	break;
    537 	}
    538 
    539 	if (syscallno == EXEC) 
    540 		fmtprint(&fmt, " = %p \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
    541 	else
    542 		fmtprint(&fmt, " = %d \"%s\" %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
    543 
    544 	up->syscalltrace = fmtstrflush(&fmt);
    545 }
    546 /*
    547  * Handle a system call.
    548  */
    549 static void
    550 syscall(Ureg *ureg)
    551 {
    552 	char *e;
    553 	ulong sp;
    554 	uchar *usp;
    555 	long	ret;
    556 	int s;
    557 	ulong scallnr;
    558 	vlong startnsec, stopnsec;
    559 
    560 	USED(startnsec);
    561 	cycles(&up->kentry);
    562 	m->syscall++;
    563 	up->insyscall = 1;
    564 	up->pc = ureg->pc;
    565 	up->dbgreg = ureg;
    566 
    567 	if(up->procctl == Proc_tracesyscall){
    568 		up->procctl = Proc_stopme;
    569 		syscallprint(ureg);
    570 		procctl(up);
    571 		if(up->syscalltrace)
    572 			free(up->syscalltrace);
    573 		up->syscalltrace = nil;
    574 		startnsec = todget(nil);
    575 	}
    576 
    577 	scallnr = ureg->ax;
    578 	up->scallnr = scallnr;
    579 	if(scallnr == RFORK && up->fpstate == FPactive){
    580 		fpsave(&up->fpsave);
    581 		up->fpstate = FPinactive;
    582 	}
    583 	spllo();
    584 
    585 	sp = ureg->usp;
    586 	up->nerrlab = 0;
    587 	ret = -1;
    588 	if(!waserror()){
    589 		if(scallnr >= nsyscall || systab[scallnr] == 0){
    590 			pprint("bad sys call number %d pc %lux\n",
    591 				scallnr, ureg->pc);
    592 			postnote(up, 1, "sys: bad sys call", NDebug);
    593 			error(Ebadarg);
    594 		}
    595 
    596 		
    597 		usp = uvalidaddr(sp, sizeof(Sargs)+BY2WD, 0);
    598 		up->s = *((Sargs*)(usp+BY2WD));
    599 		up->psstate = sysctab[scallnr];
    600 
    601 		ret = systab[scallnr](up->s.args);
    602 		poperror();
    603 	}else{
    604 		/* failure: save the error buffer for errstr */
    605 		e = up->syserrstr;
    606 		up->syserrstr = up->errstr;
    607 		up->errstr = e;
    608 		if(0 && up->pid == 1)
    609 			print("syscall %lud error %s\n", scallnr, up->syserrstr);
    610 	}
    611 	if(up->nerrlab){
    612 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
    613 	//	for(i = 0; i < NERR; i++)
    614 	//		print("sp=%lux pc=%lux\n",
    615 	//XXX			up->errlab[i].sp, up->errlab[i].pc);
    616 		panic("error stack");
    617 	}
    618 
    619 //	if(ret < 0)
    620 //		print("%d [%s] %s\n", up->pid, up->psstate, up->syserrstr);
    621 //	else
    622 //		print("%d [%s] %d\n", up->pid, up->psstate, ret);
    623 //	printmap();
    624 
    625 	/*
    626 	 *  Put return value in frame.  On the x86 the syscall is
    627 	 *  just another trap and the return value from syscall is
    628 	 *  ignored.  On other machines the return value is put into
    629 	 *  the results register by caller of syscall.
    630 	 */
    631 	ureg->ax = ret;
    632 
    633 	if(up->procctl == Proc_tracesyscall){
    634 		stopnsec = todget(nil);
    635 		up->procctl = Proc_stopme;
    636 		retprint(ureg, scallnr, startnsec, stopnsec);
    637 		s = splhi();
    638 		procctl(up);
    639 		splx(s);
    640 		if(up->syscalltrace)
    641 			free(up->syscalltrace);
    642 		up->syscalltrace = nil;
    643 	}
    644 
    645 	up->insyscall = 0;
    646 	up->psstate = 0;
    647 
    648 	if(scallnr == NOTED)
    649 		noted(ureg, *(uint32*)(up->pmmu.uzero + sp+BY2WD));
    650 
    651 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
    652 		splhi();
    653 		notify(ureg);
    654 	}
    655 	/* if we delayed sched because we held a lock, sched now */
    656 	if(up->delaysched)
    657 		sched();
    658 	kexit(ureg);
    659 }
    660 
    661 /*
    662  *  Call user, if necessary, with note.
    663  *  Pass user the Ureg struct and the note on his stack.
    664  */
    665 int
    666 notify(Ureg* ureg)
    667 {
    668 	int l;
    669 	ulong s, sp;
    670 	Note *n;
    671 	Ureg *upureg;
    672 
    673 	if(tracesyscalls)
    674 		iprint("notify\n");
    675 
    676 	if(up->procctl)
    677 		procctl(up);
    678 	if(up->nnote == 0)
    679 		return 0;
    680 
    681 	if(up->fpstate == FPactive){
    682 		fpsave(&up->fpsave);
    683 		up->fpstate = FPinactive;
    684 	}
    685 	up->fpstate |= FPillegal;
    686 
    687 	s = spllo();
    688 	qlock(&up->debug);
    689 	up->notepending = 0;
    690 	n = &up->note[0];
    691 	if(strncmp(n->msg, "sys:", 4) == 0){
    692 		l = strlen(n->msg);
    693 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
    694 			l = ERRMAX-15;
    695 		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
    696 	}
    697 
    698 	if(n->flag!=NUser && (up->notified || up->notify==0)){
    699 		if(n->flag == NDebug)
    700 			pprint("suicide: %s\n", n->msg);
    701 		qunlock(&up->debug);
    702 		pexit(n->msg, n->flag!=NDebug);
    703 	}
    704 
    705 	if(up->notified){
    706 		qunlock(&up->debug);
    707 		splhi();
    708 		return 0;
    709 	}
    710 		
    711 	if(!up->notify){
    712 		qunlock(&up->debug);
    713 		pexit(n->msg, n->flag!=NDebug);
    714 	}
    715 	sp = ureg->usp;
    716 	sp -= sizeof(Ureg);
    717 
    718 	if(!okaddr(up->notify, 1, 0)
    719 	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
    720 		pprint("suicide: bad address in notify\n");
    721 		qunlock(&up->debug);
    722 		pexit("Suicide", 0);
    723 	}
    724 
    725 	uchar *uzero;
    726 	uzero = up->pmmu.uzero;
    727 	upureg = (void*)(uzero + sp);
    728 	memmove(upureg, ureg, sizeof(Ureg));
    729 	*(uint32*)(uzero + sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
    730 	up->ureg = sp;
    731 	sp -= BY2WD+ERRMAX;
    732 	memmove((char*)(uzero + sp), up->note[0].msg, ERRMAX);
    733 	sp -= 3*BY2WD;
    734 	*(uint32*)(uzero + sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
    735 	*(uint32*)(uzero + sp+1*BY2WD) = up->ureg;	/* arg 1 is ureg* */
    736 	*(uint32*)(uzero + sp+0*BY2WD) = 0;			/* arg 0 is pc */
    737 	ureg->usp = sp;
    738 	ureg->pc = up->notify;
    739 	up->notified = 1;
    740 	up->nnote--;
    741 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
    742 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
    743 
    744 	qunlock(&up->debug);
    745 	splx(s);
    746 	return 1;
    747 }
    748 
    749 /*
    750  *   Return user to state before notify()
    751  */
    752 static void
    753 noted(Ureg* ureg, ulong arg0)
    754 {
    755 	Ureg *nureg;
    756 	ulong oureg, sp;
    757 
    758 	qlock(&up->debug);
    759 	if(arg0!=NRSTR && !up->notified) {
    760 		qunlock(&up->debug);
    761 		pprint("call to noted() when not notified\n");
    762 		pexit("Suicide", 0);
    763 	}
    764 	up->notified = 0;
    765 
    766 	up->fpstate &= ~FPillegal;
    767 
    768 	/* sanity clause */
    769 	if(!okaddr(up->ureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
    770 		pprint("bad ureg in noted or call to noted when not notified\n");
    771 		qunlock(&up->debug);
    772 		pexit("Suicide", 0);
    773 	}
    774 	
    775 	uchar *uzero;
    776 	uzero = up->pmmu.uzero;
    777 	oureg = up->ureg;
    778 	nureg = (Ureg*)(uzero + up->ureg);
    779 
    780 	/* don't let user change system flags */
    781 	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
    782 
    783 	memmove(ureg, nureg, sizeof(Ureg));
    784 
    785 	switch(arg0){
    786 	case NCONT:
    787 	case NRSTR:
    788 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
    789 			qunlock(&up->debug);
    790 			pprint("suicide: trap in noted\n");
    791 			pexit("Suicide", 0);
    792 		}
    793 		up->ureg = *(uint32*)(uzero+oureg-BY2WD);
    794 		qunlock(&up->debug);
    795 		break;
    796 
    797 	case NSAVE:
    798 		if(!okaddr(nureg->pc, BY2WD, 0)
    799 		|| !okaddr(nureg->usp, BY2WD, 0)){
    800 			qunlock(&up->debug);
    801 			pprint("suicide: trap in noted\n");
    802 			pexit("Suicide", 0);
    803 		}
    804 		qunlock(&up->debug);
    805 		sp = oureg-4*BY2WD-ERRMAX;
    806 		splhi();
    807 		ureg->sp = sp;
    808 		((uint32*)(uzero+sp))[1] = oureg;	/* arg 1 0(FP) is ureg* */
    809 		((uint32*)(uzero+sp))[0] = 0;		/* arg 0 is pc */
    810 		break;
    811 
    812 	default:
    813 		pprint("unknown noted arg 0x%lux\n", arg0);
    814 		up->lastnote.flag = NDebug;
    815 		/* fall through */
    816 		
    817 	case NDFLT:
    818 		if(up->lastnote.flag == NDebug){ 
    819 			qunlock(&up->debug);
    820 			pprint("suicide: %s\n", up->lastnote.msg);
    821 		} else
    822 			qunlock(&up->debug);
    823 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
    824 	}
    825 }
    826 
    827 long
    828 execregs(ulong entry, ulong ssize, ulong nargs)
    829 {
    830 	uint32 *sp;
    831 	Ureg *ureg;
    832 
    833 	up->fpstate = FPinit;
    834 	fpoff();
    835 
    836 	sp = (uint32*)(up->pmmu.uzero + USTKTOP - ssize);
    837 	*--sp = nargs;
    838 
    839 	ureg = up->dbgreg;
    840 	ureg->usp = (uchar*)sp - up->pmmu.uzero;
    841 //showexec(ureg->usp);
    842 	ureg->pc = entry;
    843 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
    844 }
    845 
    846 /*
    847  *  return the userpc the last exception happened at
    848  */
    849 ulong
    850 userpc(void)
    851 {
    852 	Ureg *ureg;
    853 
    854 	ureg = (Ureg*)up->dbgreg;
    855 	return ureg->pc;
    856 }
    857 
    858 /* This routine must save the values of registers the user is not permitted
    859  * to write from devproc and then restore the saved values before returning.
    860  */
    861 void
    862 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
    863 {
    864 	ulong flags;
    865 
    866 	flags = ureg->flags;
    867 	memmove(pureg, uva, n);
    868 	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
    869 }
    870 
    871 static void
    872 linkproc(void)
    873 {
    874 	spllo();
    875 	up->kpfun(up->kparg);
    876 	pexit("kproc dying", 0);
    877 }
    878 
    879 void
    880 kprocchild(Proc* p, void (*func)(void*), void* arg)
    881 {
    882 	/*
    883 	 * gotolabel() needs a word on the stack in
    884 	 * which to place the return PC used to jump
    885 	 * to linkproc().
    886 	 */
    887 	labelinit(&p->sched, (ulong)linkproc, (ulong)p->kstack+KSTACK-BY2WD);
    888 
    889 	p->kpfun = func;
    890 	p->kparg = arg;
    891 }
    892 
    893 void
    894 forkchild(Proc *p, Ureg *ureg)
    895 {
    896 	Ureg *cureg;
    897 	void *sp;
    898 
    899 	/*
    900 	 * Add 2*BY2WD to the stack to account for
    901 	 *  - the return PC
    902 	 *  - trap's argument (ur)
    903 	 */
    904 	sp = (char*)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
    905 	labelinit(&p->sched, (ulong)forkret, (ulong)sp);
    906 
    907 	cureg = (Ureg*)((char*)sp+2*BY2WD);
    908 	memmove(cureg, ureg, sizeof(Ureg));
    909 	/* return value of syscall in child */
    910 	cureg->ax = 0;
    911 
    912 	/* Things from bottom of syscall which were never executed */
    913 	p->psstate = 0;
    914 	p->insyscall = 0;
    915 }
    916 
    917 /*
    918  * Give enough context in the ureg to produce a kernel stack for
    919  * a sleeping process.  Or not.
    920  */
    921 void
    922 setkernur(Ureg* ureg, Proc* p)
    923 {
    924 	memset(ureg, 0, sizeof *ureg);
    925 }
    926 
    927 ulong
    928 dbgpc(Proc *p)
    929 {
    930 	Ureg *ureg;
    931 
    932 	ureg = p->dbgreg;
    933 	if(ureg == 0)
    934 		return 0;
    935 
    936 	return ureg->pc;
    937 }
    938 
    939 /*
    940  * floating point and all its glory.
    941  */
    942 
    943 static char* mathmsg[] =
    944 {
    945 	nil,	/* handled below */
    946 	"denormalized operand",
    947 	"division by zero",
    948 	"numeric overflow",
    949 	"numeric underflow",
    950 	"precision loss",
    951 };
    952 
    953 static void
    954 mathnote(void)
    955 {
    956 	int i;
    957 	ulong status;
    958 	char *msg, note[ERRMAX];
    959 
    960 	status = up->fpsave.status;
    961 
    962 	/*
    963 	 * Some attention should probably be paid here to the
    964 	 * exception masks and error summary.
    965 	 */
    966 	msg = "unknown exception";
    967 	for(i = 1; i <= 5; i++){
    968 		if(!((1<<i) & status))
    969 			continue;
    970 		msg = mathmsg[i];
    971 		break;
    972 	}
    973 	if(status & 0x01){
    974 		if(status & 0x40){
    975 			if(status & 0x200)
    976 				msg = "stack overflow";
    977 			else
    978 				msg = "stack underflow";
    979 		}else
    980 			msg = "invalid operation";
    981 	}
    982 	sprint(note, "sys: fp: %s fppc=0x%lux status=0x%lux", msg, up->fpsave.pc, status);
    983 	postnote(up, 1, note, NDebug);
    984 }
    985 
    986 
    987 /*
    988  *  math coprocessor emulation fault
    989  */
    990 static void
    991 mathemu(Ureg *ureg, void *v)
    992 {
    993 	if(up->fpstate & FPillegal){
    994 		/* someone did floating point in a note handler */
    995 		postnote(up, 1, "sys: floating point in note handler", NDebug);
    996 		return;
    997 	}
    998 	switch(up->fpstate){
    999 	case FPinit:
   1000 		fpinit();
   1001 		up->fpstate = FPactive;
   1002 		break;
   1003 	case FPinactive:
   1004 		/*
   1005 		 * Before restoring the state, check for any pending
   1006 		 * exceptions, there's no way to restore the state without
   1007 		 * generating an unmasked exception.
   1008 		 * More attention should probably be paid here to the
   1009 		 * exception masks and error summary.
   1010 		 */
   1011 		if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
   1012 			mathnote();
   1013 			break;
   1014 		}
   1015 		fprestore(&up->fpsave);
   1016 		up->fpstate = FPactive;
   1017 		break;
   1018 	case FPactive:
   1019 		panic("math emu pid %ld %s pc 0x%lux", 
   1020 			up->pid, up->text, ureg->pc);
   1021 		break;
   1022 	}
   1023 }
   1024 
   1025 /*
   1026  *  math coprocessor segment overrun
   1027  * TODO: When to call this?
   1028  */
   1029 void
   1030 mathover(Ureg *u, void *v)
   1031 {
   1032 	pexit("math overrun", 0);
   1033 }
   1034 
   1035 /*
   1036  *  math coprocessor error
   1037  * TODO: When to call this?
   1038  */
   1039 void
   1040 matherror(Ureg *ur, void *v)
   1041 {
   1042 	/*
   1043 	 *  a write cycle to port 0xF0 clears the interrupt latch attached
   1044 	 *  to the error# line from the 387
   1045 	 */
   1046 //	if(!(m->cpuiddx & 0x01))
   1047 //		outb(0xF0, 0xFF);
   1048 
   1049 	/*
   1050 	 *  save floating point state to check out error
   1051 	 */
   1052 	fpenv(&up->fpsave);
   1053 	mathnote();
   1054 
   1055 	if(!okaddr(ur->pc, 1, 0))
   1056 		panic("fp: status %ux fppc=0x%lux pc=0x%lux",
   1057 			up->fpsave.status, up->fpsave.pc, ur->pc);
   1058 }
   1059 
   1060 /*
   1061  *  set up floating point for a new process
   1062  */
   1063 void
   1064 procsetup(Proc*p)
   1065 {
   1066 	p->fpstate = FPinit;
   1067 	fpoff();
   1068 }
   1069 
   1070 void
   1071 procrestore(Proc *p)
   1072 {
   1073 	uvlong t;
   1074 
   1075 	if(p->kp)
   1076 		return;
   1077 	cycles(&t);
   1078 	p->pcycles -= t;
   1079 }
   1080 
   1081 /*
   1082  *  Save the mach dependent part of the process state.
   1083  */
   1084 void
   1085 procsave(Proc *p)
   1086 {
   1087 	uvlong t;
   1088 
   1089 	cycles(&t);
   1090 	p->pcycles += t;
   1091 	if(p->fpstate == FPactive){
   1092 		if(p->state == Moribund)
   1093 			fpclear();
   1094 		else{
   1095 			/*
   1096 			 * Fpsave() stores without handling pending
   1097 			 * unmasked exeptions. Postnote() can't be called
   1098 			 * here as sleep() already has up->rlock, so
   1099 			 * the handling of pending exceptions is delayed
   1100 			 * until the process runs again and generates an
   1101 			 * emulation fault to activate the FPU.
   1102 			 */
   1103 			fpsave(&p->fpsave);
   1104 		}
   1105 		p->fpstate = FPinactive;
   1106 	}
   1107 }