shithub: front

Download patch

ref: 78c2dfe8087d4808e13aeabb6a0e3d1dc696d728
parent: 4d99c9c4c14b9bec61773bd7c84f296b8aa1ec2b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jul 6 16:33:51 EDT 2025

kernel: move core of note handling logic into port/sysproc.c

I believe holding up->debug qlock while touching the stack
is a problem if the fault handler runs into trouble,
as it would not be able to deliver any notes.

To address this, lets simplify what has to be done per arch
for notify() and noted() and provide a donotify() wrapper and
do most of the checking in sysnoted().

The per-arch notify() function now just needs to push
the note on the stack and prepare registers for the note
handler.

The per-arch notify() function now gets previous note
ureg passed in and just needs to restore it (by calling
setregisters() function) and check validity.

The chaining needed for NSAVE/NRSTR is handled by
donotify() and sysnoted() now, per arch doesnt needs
to care other than reserve a pointer sized slot before
the Ureg returned by notify().

Fpu state handling is now exposed: each arch needs to
provide fpunotify() and fpunoted() functions. They'r
called with up->debug qlock held and interrupts off.

Rename Proc.ureg to Proc.noteureg (shouldnt be touched by
arch specific part).

--- a/sys/src/9/arm64/fns.h
+++ b/sys/src/9/arm64/fns.h
@@ -95,8 +95,6 @@
 extern void fpuprocrestore(Proc*);
 extern void fpukenter(Ureg*);
 extern void fpukexit(Ureg*);
-extern void fpunotify(Proc*);
-extern void fpunoted(Proc*);
 extern void mathtrap(Ureg*);
 
 /* trap */
--- a/sys/src/9/arm64/trap.c
+++ b/sys/src/9/arm64/trap.c
@@ -176,7 +176,7 @@
 	splhi();
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 	if(type != 0x07 && type != 0x2C)
@@ -197,7 +197,7 @@
 		returnto(noteret);
 
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 
 	if(up->delaysched)
 		sched();
@@ -206,126 +206,68 @@
 	fpukexit(ureg);
 }
 
-int
-notify(Ureg *ureg)
+Ureg*
+notify(Ureg *ureg, char *msg)
 {
+	Ureg *nureg;
 	uintptr sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->sp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
 	sp = STACKALIGN(sp);
 
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
 	|| ((uintptr) up->notify & 3) != 0
-	|| (sp & 7) != 0){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify: handler=%#p sp=%#p\n",
-			up->notify, sp);
-		pexit("Suicide", 0);
-	}
+	|| (sp & 7) != 0)
+		return nil;
 
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(uintptr*)(sp+2*BY2WD) = sp+3*BY2WD;
-	*(uintptr*)(sp+1*BY2WD) = (uintptr)up->ureg;
-	ureg->r0 = (uintptr) up->ureg;
+	*(uintptr*)(sp+1*BY2WD) = (uintptr)nureg;
+	ureg->r0 = (uintptr)nureg;
 	ureg->sp = sp;
-	ureg->pc = (uintptr) up->notify;
+	ureg->pc = (uintptr)up->notify;
 	ureg->link = 0;
 
-	splhi();
-	fpunotify(up);
-	qunlock(&up->debug);
-
-	return 1;
+	return nureg;
 }
 
-void
-noted(Ureg *ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	uintptr oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted(up);
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;
-	
 	oureg = (uintptr) nureg;
-	if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 7) != 0){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
+	if((oureg & 7) != 0)
+		return -1;
 
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 	
 	switch(arg0){
 	case NCONT: case NRSTR:
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(ureg->sp, BY2WD, 0) ||
-				(ureg->pc & 3) != 0 || (ureg->sp & 7) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg *) (*(uintptr*) (oureg - BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(ureg->sp, BY2WD, 0)
+		|| (ureg->pc & 3) != 0 || (ureg->sp & 7) != 0)
+			return -1;
 		break;
-	
 	case NSAVE:
 		sp = oureg - 4 * BY2WD - ERRMAX;
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(sp, 4 * BY2WD, 1) ||
-				(nureg->pc & 3) != 0 || (sp & 7) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(sp, 4 * BY2WD, 1)
+		|| (nureg->pc & 3) != 0 || (sp & 7) != 0)
+			return -1;
 		ureg->sp = sp;
 		ureg->r0 = (uintptr) oureg;
 		((uintptr *) sp)[1] = oureg;
 		((uintptr *) sp)[0] = 0;
 		break;
-	
-	default:
-		up->lastnote->flag = NDebug;
-	
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
 	}
+	return 0;
 }
 
 void
--- a/sys/src/9/bcm/fns.h
+++ b/sys/src/9/bcm/fns.h
@@ -111,8 +111,6 @@
 extern int fpudevprocio(Proc*, void*, long, uintptr, int);
 extern FPalloc *fpalloc(void);
 extern void fpuinit(void);
-extern void fpunoted(void);
-extern void fpunotify(void);
 extern void fpuprocrestore(Proc*);
 extern void fpuprocsave(Proc*);
 extern void fpuprocfork(Proc*);
--- a/sys/src/9/bcm/trap.c
+++ b/sys/src/9/bcm/trap.c
@@ -36,7 +36,6 @@
 };
 
 extern int irq(Ureg*);
-extern int notify(Ureg*);
 
 /*
  *  set up for exceptions
@@ -259,7 +258,7 @@
 
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
--- a/sys/src/9/bcm/vfp3.c
+++ b/sys/src/9/bcm/vfp3.c
@@ -236,13 +236,13 @@
  * checked in the Device Not Available handler.
  */
 void
-fpunotify(void)
+fpunotify(Proc *p)
 {
-	if(up->fpstate == FPactive){
-		fpsave(up->fpsave);
-		up->fpstate = up->fpsave->fpstate = FPinactive;
+	if(p->fpstate == FPactive){
+		fpsave(p->fpsave);
+		p->fpstate = p->fpsave->fpstate = FPinactive;
 	}
-	up->fpstate |= FPnotify;
+	p->fpstate |= FPnotify;
 }
 
 /*
@@ -251,22 +251,22 @@
  * Clear the flag set above in fpunotify().
  */
 void
-fpunoted(void)
+fpunoted(Proc *p)
 {
-	if(up->fpstate & FPnotify){
-		up->fpstate &= ~FPnotify;
+	if(p->fpstate & FPnotify){
+		p->fpstate &= ~FPnotify;
 	} else {
 		FPalloc *o;
 
-		if(up->fpstate == FPactive)
+		if(p->fpstate == FPactive)
 			fpoff();
-		if((o = up->ofpsave) != nil) {
-			up->ofpsave = nil;
-			free(up->fpsave);
-			up->fpsave = o;
-			up->fpstate = o->fpstate;
+		if((o = p->ofpsave) != nil) {
+			p->ofpsave = nil;
+			free(p->fpsave);
+			p->fpsave = o;
+			p->fpstate = o->fpstate;
 		} else {
-			up->fpstate = FPinit;
+			p->fpstate = FPinit;
 		}
 	}
 }
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -94,8 +94,6 @@
 extern void fpuprocrestore(Proc*);
 extern void fpukenter(Ureg*);
 extern void fpukexit(Ureg*);
-extern void fpunotify(Proc*);
-extern void fpunoted(Proc*);
 extern void mathtrap(Ureg*);
 
 /* trap */
--- a/sys/src/9/cycv/trap.c
+++ b/sys/src/9/cycv/trap.c
@@ -179,7 +179,7 @@
 	splhi();
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
@@ -194,7 +194,7 @@
 	scallnr = ureg->r0;
 	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	if(up->delaysched)
 		sched();
 	kexit(ureg);
@@ -201,19 +201,19 @@
 }
 
 void
-fpunotify(void)
+fpunotify(Proc *p)
 {
-	if(up->fpstate == FPactive){
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
+	if(p->fpstate == FPactive){
+		fpsave(p->fpsave);
+		p->fpstate = FPinactive;
 	}
-	up->fpstate |= FPnotify;
+	p->fpstate |= FPnotify;
 }
 
 void
-fpunoted(void)
+fpunoted(Proc *p)
 {
-	up->fpstate &= ~FPnotify;
+	p->fpstate &= ~FPnotify;
 }
 
 FPsave*
@@ -222,96 +222,52 @@
 	return nil;
 }
 
-int
-notify(Ureg *ureg)
+Ureg*
+notify(Ureg *ureg, char *msg)
 {
+	Ureg *nureg;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->sp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
 
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
 	|| ((uintptr) up->notify & 3) != 0
-	|| (sp & 3) != 0){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
+	|| (sp & 3) != 0)
+		return nil;
 
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
-	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
-	ureg->r0 = (uintptr) up->ureg;
+	*(ulong*)(sp+1*BY2WD) = (ulong)nureg;
+	ureg->r0 = (uintptr)nureg;
 	ureg->sp = sp;
-	ureg->pc = (uintptr) up->notify;
+	ureg->pc = (uintptr)up->notify;
 	ureg->r14 = 0;
-
-	splhi();
-	fpunotify();
-	qunlock(&up->debug);
-	return 1;
+	return nureg;
 }
 
-void
-noted(Ureg *ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 	
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted();
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;
 	oureg = (ulong) nureg;
-	if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
+	if((oureg & 3) != 0)
+		return -1;
 	
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 	
 	switch(arg0){
 	case NCONT: case NRSTR:
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(ureg->sp, BY2WD, 0) ||
-				(ureg->pc & 3) != 0 || (ureg->sp & 3) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(ureg->sp, BY2WD, 0)
+		|| (ureg->pc & 3) != 0 || (ureg->sp & 3) != 0)
+			return -1;
 		break;
 	
 	case NSAVE:
@@ -318,26 +274,15 @@
 		sp = oureg - 4 * BY2WD - ERRMAX;
 		ureg->sp = sp;
 		ureg->r0 = (uintptr) oureg;
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(ureg->sp, 4*BY2WD, 1) ||
-				(ureg->pc & 3) != 0 || (ureg->sp & 3) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(ureg->sp, 4*BY2WD, 1)
+		|| (ureg->pc & 3) != 0 || (ureg->sp & 3) != 0)
+			return -1;
 		((ulong *) sp)[1] = oureg;
 		((ulong *) sp)[0] = 0;
 		break;
-	
-	default:
-		up->lastnote->flag = NDebug;
-	
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
 	}
+	return 0;
 }
 
 
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -97,8 +97,6 @@
 extern void fpuprocrestore(Proc*);
 extern void fpukenter(Ureg*);
 extern void fpukexit(Ureg*);
-extern void fpunotify(Proc*);
-extern void fpunoted(Proc*);
 extern void mathtrap(Ureg*);
 
 /* trap */
--- a/sys/src/9/kw/fns.h
+++ b/sys/src/9/kw/fns.h
@@ -90,8 +90,6 @@
 extern int fpiarm(Ureg*);
 extern int fpudevprocio(Proc*, void*, long, uintptr, int);
 extern void fpuinit(void);
-extern void fpunoted(void);
-extern void fpunotify(void);
 extern void fpuprocrestore(Proc*);
 extern void fpuprocsave(Proc*);
 extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/kw/trap.c
+++ b/sys/src/9/kw/trap.c
@@ -17,8 +17,6 @@
 	Nvecs = 256,
 };
 
-extern int notify(Ureg*);
-
 extern int ldrexvalid;
 
 typedef struct Vctl Vctl;
@@ -468,7 +466,7 @@
 
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
--- a/sys/src/9/lx2k/fns.h
+++ b/sys/src/9/lx2k/fns.h
@@ -97,8 +97,6 @@
 extern void fpuprocrestore(Proc*);
 extern void fpukenter(Ureg*);
 extern void fpukexit(Ureg*);
-extern void fpunotify(Proc*);
-extern void fpunoted(Proc*);
 extern void mathtrap(Ureg*);
 
 /* trap */
--- a/sys/src/9/mt7688/syscall.c
+++ b/sys/src/9/mt7688/syscall.c
@@ -24,7 +24,7 @@
 	if(dosyscall(scallnr, (Sargs*)ur->sp, &ur->r1) == 0)
 		ur->pc += 4;
 	if(up->procctl || up->nnote)
-		notify(ur);
+		donotify(ur);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
@@ -34,15 +34,15 @@
 }
 
 void
-fpunotify(void)
+fpunotify(Proc *p)
 {
-	up->fpstate |= FPnotify;
+	p->fpstate |= FPnotify;
 }
 
 void
-fpunoted(void)
+fpunoted(Proc *p)
 {
-	up->fpstate &= ~FPnotify;
+	p->fpstate &= ~FPnotify;
 }
 
 FPsave*
@@ -51,38 +51,19 @@
 	return nil;
 }
 
-int
-notify(Ureg *ur)
+Ureg*
+notify(Ureg *ur, char *msg)
 {
+	Ureg *nur;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ur);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ur->usp - sizeof(Ureg) - BY2WD; /* spim libc */
 
-	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
-	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
-		iprint("suicide: bad address or sp in notify\n");
-		qunlock(&up->debug);
-		pexit("Suicide", 0);
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
 
-	memmove((Ureg*)sp, ur, sizeof(Ureg));	/* push user regs */
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nur = (Ureg*)sp;
+	memmove(nur, ur, sizeof(Ureg));	/* push user regs */
 
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);	/* push err string */
@@ -89,8 +70,8 @@
 
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
-	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
-	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
+	ur->r1 = (long)nur;			/* arg 1 is ureg* */
+	((ulong*)sp)[1] = (ulong)nur;		/* arg 1 0(FP) is ureg* */
 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
 	ur->usp = sp;
 	/*
@@ -98,11 +79,7 @@
 	 * were being called.
 	 */
 	ur->pc = (ulong)up->notify;
-
-	fpunotify();
-	qunlock(&up->debug);
-	splhi();
-	return 1;
+	return nur;
 }
 
 
@@ -109,30 +86,14 @@
 /*
  * Return user to state before notify(); called from user's handler.
  */
-void
-noted(Ureg *kur, int arg0)
+int
+noted(Ureg *kur, Ureg *nur, int arg0)
 {
-	Ureg *nur;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		fpunoted();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nur = up->ureg;
-
 	oureg = (ulong)nur;
-	if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad up->ureg in noted or call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
+	if(oureg & (BY2WD-1))
+		return -1;
 
 	setregisters(kur, (char*)kur, (char*)nur, sizeof(Ureg));
 
@@ -139,13 +100,8 @@
 	switch(arg0) {
 	case NCONT:
 	case NRSTR:				/* only used by APE */
-		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0))
+			return -1;
 		break;
 
 	case NSAVE:				/* only used by APE */
@@ -152,26 +108,13 @@
 		sp = oureg-4*BY2WD-ERRMAX;
 		kur->r1 = oureg;		/* arg 1 is ureg* */
 		kur->usp = sp;
-		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, 4*BY2WD, 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, 4*BY2WD, 1))
+			return -1;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+	return 0;
 }
 
 
--- a/sys/src/9/mt7688/trap.c
+++ b/sys/src/9/mt7688/trap.c
@@ -243,7 +243,7 @@
 	splhi();
 
 	if(user){
-		notify(ur);
+		donotify(ur);
 		/* replicate fpstate to ureg status */
 	//	if(up->fpstate != FPactive)
 	//		ur->status &= ~CU1;
--- a/sys/src/9/mtx/trap.c
+++ b/sys/src/9/mtx/trap.c
@@ -614,51 +614,28 @@
  *  Call user, if necessary, with note.
  *  Pass user the Ureg struct and the note on his stack.
  */
-int
-notify(Ureg* ur)
+Ureg*
+notify(Ureg* ur, char *msg)
 {
+	Ureg *nur;
 	ulong s, sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	s = spllo();
-	qlock(&up->debug);
-	msg = popnote(ur);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ur->usp & ~(BY2V-1);
 	sp -= sizeof(Ureg);
-
-	if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
-	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
-		qunlock(&up->debug);
-		pprint("suicide: bad address or sp in notify\n");
-		pexit("Suicide", 0);
-	}
-
-	memmove((Ureg*)sp, ur, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
+	nur = (Ureg*)sp;
+	memmove(nur, ur, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
-	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
-	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
+	ur->r1 = (long)nur;			/* arg 1 is ureg* */
+	((ulong*)sp)[1] = (ulong)nur;		/* arg 1 0(FP) is ureg* */
 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
 	ur->usp = sp;
 	ur->pc = (ulong)up->notify;
-	qunlock(&up->debug);
-	splx(s);
-	return 1;
+	return nur;
 }
 
 
@@ -665,67 +642,30 @@
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(arg0!=NRSTR && !up->notified) {
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-	up->notified = 0;
-
-	nureg = up->ureg;	/* pointer to user returned Ureg struct */
-
-	/* sanity clause */
 	oureg = (ulong)nureg;
-	if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
 
-	memmove(ureg, nureg, sizeof(Ureg));
+	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 
 	switch(arg0){
 	case NCONT:
 	case NRSTR:
-		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0))
+			return -1;
 		break;
-
 	case NSAVE:
 		if(!okaddr(nureg->pc, BY2WD, 0)
-		|| !okaddr(nureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		|| !okaddr(nureg->usp, BY2WD, 0))
+			return -1;
 		sp = oureg-4*BY2WD-ERRMAX;
-		splhi();
 		ureg->sp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-		
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+	return 0;
 }
--- a/sys/src/9/omap/fns.h
+++ b/sys/src/9/omap/fns.h
@@ -105,8 +105,6 @@
 extern int fpiarm(Ureg*);
 extern int fpudevprocio(Proc*, void*, long, uintptr, int);
 extern void fpuinit(void);
-extern void fpunoted(void);
-extern void fpunotify(void);
 extern void fpuprocrestore(Proc*);
 extern void fpuprocsave(Proc*);
 extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/omap/softfpu.c
+++ b/sys/src/9/omap/softfpu.c
@@ -20,7 +20,7 @@
 }
 
 void
-fpunotify(void)
+fpunotify(Proc*)
 {
 	/*
 	 * Called when a note is about to be delivered to a
@@ -32,7 +32,7 @@
 }
 
 void
-fpunoted(void)
+fpunoted(Proc*)
 {
 	/*
 	 * Called from sysnoted() via the machine-dependent
--- a/sys/src/9/omap/syscall.c
+++ b/sys/src/9/omap/syscall.c
@@ -10,137 +10,71 @@
 
 #include "arm.h"
 
-typedef struct {
-	uintptr	ip;
-	Ureg*	arg0;
-	char*	arg1;
-	char	msg[ERRMAX];
-	Ureg*	old;
-	Ureg	ureg;
-} NFrame;
-
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* cur, int arg0)
+int
+noted(Ureg* ureg, Ureg *nureg, int arg0)
 {
-	NFrame *nf;
+	ulong oureg, sp;
+	
+	oureg = (ulong) nureg;
+	if((oureg & 3) != 0)
+		return -1;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted();
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nf = up->ureg;
-
-	/* sanity clause */
-	if(!okaddr((uintptr)nf, sizeof(NFrame), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted %#p\n", nf);
-		pexit("Suicide", 0);
-	}
-
-	setregisters(cur, (char*)cur, (char*)&nf->ureg, sizeof(Ureg));
-
-	switch((int)arg0){
-	case NCONT:
-	case NRSTR:
-		if(!okaddr(cur->pc, BY2WD, 0) || !okaddr(cur->sp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = nf->old;
-		qunlock(&up->debug);
+	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
+	
+	switch(arg0){
+	case NCONT: case NRSTR:
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(ureg->sp, BY2WD, 0)
+		|| (ureg->pc & 3) != 0 || (ureg->sp & 3) != 0)
+			return -1;
 		break;
+	
 	case NSAVE:
-		cur->sp = (uintptr)nf;
-		cur->r0 = (uintptr)&nf->ureg;
-		if(!okaddr(cur->pc, BY2WD, 0) || !okaddr(cur->sp, sizeof(NFrame), 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
-		nf->arg1 = nf->msg;
-		nf->arg0 = &nf->ureg;
-		nf->ip = 0;
+		sp = oureg - 4 * BY2WD - ERRMAX;
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(sp, 4 * BY2WD, 1)
+		|| (ureg->pc & 3) != 0 || (sp & 3) != 0)
+			return -1;
+		ureg->sp = sp;
+		ureg->r0 = (uintptr) oureg;
+		((ulong *) sp)[1] = oureg;
+		((ulong *) sp)[0] = 0;
 		break;
-	default:
-		up->lastnote->flag = NDebug;
-		/*FALLTHROUGH*/
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
 	}
+	return 0;
 }
 
-/*
- *  Call user, if necessary, with note.
- *  Pass user the Ureg struct and the note on his stack.
- */
-int
-notify(Ureg* ureg)
+Ureg*
+notify(Ureg *ureg, char *msg)
 {
-	uintptr sp;
-	NFrame *nf;
-	char *msg;
+	Ureg *nureg;
+	ulong sp;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
+	sp = ureg->sp;
+	sp -= 256;	/* debugging: preserve context causing problem */
+	sp -= sizeof(Ureg);
 
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+	|| ((uintptr) up->notify & 3) != 0
+	|| (sp & 3) != 0)
+		return nil;
 
-	if(!okaddr((uintptr)up->notify, 1, 0)){
-		qunlock(&up->debug);
-		pprint("suicide: notify function address %#p\n", up->notify);
-		pexit("Suicide", 0);
-	}
-
-	sp = ureg->sp - sizeof(NFrame);
-	if(!okaddr(sp, sizeof(NFrame), 1)){
-		qunlock(&up->debug);
-		pprint("suicide: notify stack address %#p\n", sp);
-		pexit("Suicide", 0);
-	}
-
-	nf = (void*)sp;
-	memmove(&nf->ureg, ureg, sizeof(Ureg));
-	nf->old = up->ureg;
-	up->ureg = nf;
-	memmove(nf->msg, msg, ERRMAX);
-	nf->arg1 = nf->msg;
-	nf->arg0 = &nf->ureg;
-	nf->ip = 0;
-
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
+	sp -= BY2WD+ERRMAX;
+	memmove((char*)sp, msg, ERRMAX);
+	sp -= 3*BY2WD;
+	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
+	*(ulong*)(sp+1*BY2WD) = (ulong)nureg;
+	ureg->r0 = (uintptr)nureg;
 	ureg->sp = sp;
 	ureg->pc = (uintptr)up->notify;
-	ureg->r0 = (uintptr)nf->arg0;
+	ureg->r14 = 0;
 
-	splhi();
-	fpunotify();
-	qunlock(&up->debug);
-
-	return 1;
+	return nureg;
 }
 
 void
@@ -154,7 +88,7 @@
 	scallnr = ureg->r0;
 	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
--- a/sys/src/9/omap/trap.c
+++ b/sys/src/9/omap/trap.c
@@ -17,8 +17,6 @@
 	Bi2long = BI2BY * sizeof(long),
 };
 
-extern int notify(Ureg*);
-
 extern int ldrexvalid;
 
 /* omap35x intc (aka mpu_intc) */
@@ -587,7 +585,7 @@
 	splhi();
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -20,8 +20,6 @@
 void	fpuprocfork(Proc*);
 void	fpuprocsave(Proc*);
 void	fpuprocrestore(Proc*);
-void	fpunotify(Proc*);
-void	fpunoted(Proc*);
 int	cpuidentify(void);
 void	cpuidprint(void);
 void	(*cycles)(uvlong*);
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -206,7 +206,7 @@
 
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
@@ -444,7 +444,7 @@
 	scallnr = ureg->ax;
 	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->ax);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
@@ -455,47 +455,26 @@
  *  Call user, if necessary, with note.
  *  Pass user the Ureg struct and the note on his stack.
  */
-int
-notify(Ureg* ureg)
+Ureg*
+notify(Ureg* ureg, char *msg)
 {
+	Ureg *nureg;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->usp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
-if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
-	up->text, up->pid, ureg->pc, ureg->usp, sp, msg);
 
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
 
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
-	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
+	*(ulong*)(sp+1*BY2WD) = (ulong)nureg;		/* arg 1 is ureg* */
 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
 	ureg->usp = sp;
 	ureg->pc = (ulong)up->notify;
@@ -502,42 +481,18 @@
 	ureg->cs = UESEL;
 	ureg->ss = ureg->ds = ureg->es = UDSEL;
 
-	splhi();
-	fpunotify(up);
-	qunlock(&up->debug);
-	return 1;
+	return nureg;
 }
 
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* ureg, int arg0)
+int
+noted(Ureg* ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted(up);
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;	/* pointer to user returned Ureg struct */
-
-	/* sanity clause */
 	oureg = (ulong)nureg;
-	if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
 
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 
@@ -545,38 +500,21 @@
 	case NCONT:
 	case NRSTR:
 if(0) print("%s %lud: noted %#p %#p\n", up->text, up->pid, ureg->pc, ureg->usp);
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->usp, BY2WD, 0))
+			return -1;
 		break;
 
 	case NSAVE:
 		sp = oureg-4*BY2WD-ERRMAX;
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4*BY2WD, 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4*BY2WD, 1))
+			return -1;
 		ureg->usp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+
+	return 0;
 }
 
 uintptr
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -41,8 +41,6 @@
 void	fpuprocrestore(Proc*);
 void	fpuprocsave(Proc*);
 void	fpuprocsetup(Proc*);
-void	fpunotify(Proc*);
-void	fpunoted(Proc*);
 u64int	getcr0(void);
 u64int	getcr2(void);
 u64int	getcr3(void);
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -177,7 +177,7 @@
 	splhi();
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 	if(vno != VectorCNA)
@@ -424,7 +424,7 @@
 	scallnr = ureg->bp;	/* RARG */
 	if(dosyscall(scallnr, (Sargs*)(ureg->sp+BY2WD), &ureg->ax))
 		((void**)&ureg)[-1] = (void*)noteret;	/* loads RARG */
-	if((up->procctl || up->nnote) && notify(ureg))
+	if((up->procctl || up->nnote) && donotify(ureg))
 		((void**)&ureg)[-1] = (void*)noteret;	/* loads RARG */
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
@@ -433,95 +433,46 @@
 	fpukexit(ureg);
 }
 
-/*
- *  Call user, if necessary, with note.
- *  Pass user the Ureg struct and the note on his stack.
- */
-int
-notify(Ureg* ureg)
+Ureg*
+notify(Ureg *ureg, char *msg)
 {
+	Ureg *nureg;
 	uintptr sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->sp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
-if(0) print("%s %lud: notify %#p %#p %#p %s\n",
-	up->text, up->pid, ureg->pc, ureg->sp, sp, msg);
 
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
 
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (void*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	((uintptr*)sp)[2] = sp + 3*BY2WD;	/* arg2 string */
-	((uintptr*)sp)[1] = (uintptr)up->ureg;	/* arg1 is ureg* */
+	((uintptr*)sp)[1] = (uintptr)nureg;	/* arg1 is ureg* */
 	((uintptr*)sp)[0] = 0;			/* arg0 is pc */
+
 	ureg->sp = sp;
 	ureg->pc = (uintptr)up->notify;
-	ureg->bp = (uintptr)up->ureg;		/* arg1 passed in RARG */
+	ureg->bp = (uintptr)nureg;		/* arg1 passed in RARG */
 	ureg->cs = UESEL;
 	ureg->ss = UDSEL;
 
-	splhi();
-	fpunotify(up);
-	qunlock(&up->debug);
-
-	return 1;
+	return nureg;
 }
 
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	uintptr oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted(up);
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;	/* pointer to user returned Ureg struct */
-
-	/* sanity clause */
 	oureg = (uintptr)nureg;
-	if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
 
 	/* don't let user change system flags or segment registers */
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
@@ -529,40 +480,21 @@
 	switch(arg0){
 	case NCONT:
 	case NRSTR:
-if(0) print("%s %lud: noted %#p %#p\n", up->text, up->pid, ureg->pc, ureg->sp);
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->sp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(uintptr*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->sp, BY2WD, 0))
+			return -1;
 		break;
 
 	case NSAVE:
 		sp = oureg-4*BY2WD-ERRMAX;
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4 * BY2WD, 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4 * BY2WD, 1))
+			return -1;
 		ureg->sp = sp;
 		ureg->bp = oureg;		/* arg 1 passed in RARG */
 		((uintptr*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((uintptr*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+	return 0;
 }
 
 uintptr
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -789,7 +789,7 @@
 	uintptr	qpc;		/* pc calling last blocking qlock */
 	QLock	*eql;		/* interruptable eqlock */
 
-	void	*ureg;		/* User registers for notes */
+	void	*noteureg;	/* User registers for notes */
 	void	*dbgreg;	/* User registers for devproc */
 
 	PFPU;			/* machine specific fpu state */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -82,6 +82,7 @@
 Walkqid*	devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
 int		devwstat(Chan*, uchar*, int);
 Dir*		dirchanstat(Chan *);
+int		donotify(Ureg*);
 int		dosyscall(ulong, Sargs*, uintptr*);
 void		drawactive(int);
 void		drawcmap(void);
@@ -121,6 +122,8 @@
 void		forceclosefgrp(void);
 void		forkchild(Proc*, Ureg*);
 void		forkret(void);
+void		fpunotify(Proc*);
+void		fpunoted(Proc*);
 void		free(void*);
 void		freeb(Block*);
 void		freeblist(Block*);
@@ -224,8 +227,8 @@
 Rgrp*		newrgrp(void);
 Proc*		newproc(void);
 _Noreturn void	nexterror(void);
-int		notify(Ureg*);
-void		noted(Ureg*, int);
+Ureg*		notify(Ureg*, char*);
+int		noted(Ureg*, Ureg*, int);
 FPsave*		notefpsave(Proc*);
 ulong		nkpages(Confmem*);
 uvlong		ns2fastticks(uvlong);
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -85,6 +85,7 @@
 sdvirtio10.$O:	../port/sd.h ../port/pci.h /$objtype/include/ureg.h
 trap.$O:	/$objtype/include/ureg.h
 proc.$O:	/$objtype/include/ureg.h
+sysproc.$O:	/$objtype/include/ureg.h
 devproc.$O:	/$objtype/include/ureg.h
 portclock.$O:	/$objtype/include/ureg.h
 userinit.$O:	initcode.i
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -715,7 +715,7 @@
 	p->kfpstate = FPinit;
 #endif
 	p->procctl = 0;
-	p->ureg = nil;
+	p->noteureg = nil;
 	p->dbgreg = nil;
 	p->nerrlab = 0;
 	p->errstr = p->errbuf0;
@@ -1362,7 +1362,7 @@
 	freenote(up->lastnote);
 	up->lastnote = nil;
 	up->notified = 0;
-	up->ureg = nil;
+	up->noteureg = nil;
 	up->dbgreg = nil;
 
 	/* release debuggers */
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -4,6 +4,7 @@
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
+#include	"ureg.h"
 #include	"../port/error.h"
 #include	"edf.h"
 
@@ -665,7 +666,7 @@
 	up->lastnote = nil;
 	up->notify = nil;
 	up->notified = 0;
-	up->ureg = nil;
+	up->noteureg = nil;
 	up->privatemem = 0;
 	up->noswap = 0;
 	up->pcycles = -up->kentry;
@@ -847,15 +848,94 @@
 	return 0;
 }
 
+int
+donotify(Ureg *ureg)
+{
+	Ureg *nureg;
+	char *msg;
+
+	if(up->procctl)
+		procctl();
+	if(up->nnote == 0)
+		return 0;
+
+	spllo();
+	qlock(&up->debug);
+	msg = popnote(ureg);
+	if(msg == nil){
+		qunlock(&up->debug);
+		splhi();
+		return 0;
+	}
+	splhi();
+	fpunotify(up);
+	spllo();
+	qunlock(&up->debug);
+
+	if(up->notify == nil
+	|| (nureg = notify(ureg, msg)) == nil){
+		if(up->lastnote->flag == NDebug)
+			pprint("suicide: %s\n", msg);
+		pexit(msg, up->lastnote->flag!=NDebug);
+	}
+
+	/* word under Ureg is old ureg */
+	*(Ureg**)((uintptr)nureg-BY2WD) = up->noteureg;
+	up->noteureg = nureg;
+
+	splhi();
+	return 1;
+}
+
 uintptr
 sysnoted(va_list list)
 {
+	Ureg *nureg;
 	int arg;
 
 	arg = va_arg(list, int);
-	if(arg != NRSTR && !up->notified)
-		error(Egreg);
-	noted(up->dbgreg, arg);
+
+	qlock(&up->debug);
+	if(up->notified){
+		splhi();
+		fpunoted(up);
+		spllo();
+	} else if(arg!=NRSTR){
+		qunlock(&up->debug);
+		error(Ebadarg);
+	}
+	qunlock(&up->debug);
+
+	nureg = up->noteureg;
+	if(!okaddr((uintptr)nureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
+		pprint("suicide: bad ureg in noted or call to noted when not notified\n");
+		pexit("Suicide", 0);
+	}
+
+	switch(arg){
+	case NCONT:
+	case NRSTR:
+		/* word under Ureg is old ureg */
+		up->noteureg = *(Ureg**)((uintptr)nureg-BY2WD);
+		/* wet floor */
+	case NSAVE:
+		if(noted(up->dbgreg, nureg, arg)){
+			pprint("suicide: trap in noted\n");
+			pexit("Suicide", 0);
+		}
+		break;
+	default:
+		up->lastnote->flag = NDebug;
+		/* fall through */
+	case NDFLT:
+		if(up->lastnote->flag == NDebug)
+			pprint("suicide: %s\n", up->lastnote->msg);
+		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
+	}
+
+	/* allow next note */
+	up->notified = 0;
+
 	return 0;
 }
 
--- a/sys/src/9/ppc/trap.c
+++ b/sys/src/9/ppc/trap.c
@@ -279,7 +279,7 @@
 	splhi();
 
 	if(user) {
-		notify(ureg);
+		donotify(ureg);
 		if(up->fpstate != FPactive)
 			ureg->srr1 &= ~MSR_FP;
 		kexit(ureg);
@@ -573,7 +573,7 @@
 	scallnr = ureg->r3;
 	dosyscall(scallnr, (Sargs*)(ureg->usp+BY2WD), &ureg->r3);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
@@ -590,57 +590,28 @@
  *  Call user, if necessary, with note.
  *  Pass user the Ureg struct and the note on his stack.
  */
-int
-notify(Ureg* ur)
+Ureg*
+notify(Ureg* ur, char *msg)
 {
+	Ureg *nur;
 	ulong s, sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	if(up->fpstate == FPactive){
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
-	}
-	up->fpstate |= FPnotify;
-
-	s = spllo();
-	qlock(&up->debug);
-	msg = popnote(ur);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ur->usp & ~(BY2V-1);
 	sp -= sizeof(Ureg);
-
-	if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
-	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
-		qunlock(&up->debug);
-		pprint("suicide: bad address or sp in notify\n");
-		pexit("Suicide", 0);
-	}
-
-	memmove((Ureg*)sp, ur, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
+	nur = (Ureg*)sp;
+	memmove(nur, ur, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
-	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
-	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
+	ur->r1 = (long)nur;			/* arg 1 is ureg* */
+	((ulong*)sp)[1] = (ulong)nur;		/* arg 1 0(FP) is ureg* */
 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
 	ur->usp = sp;
 	ur->pc = (ulong)up->notify;
-	qunlock(&up->debug);
-	splx(s);
-	return 1;
+	return nur;
 }
 
 
@@ -647,68 +618,30 @@
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(arg0!=NRSTR && !up->notified) {
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-	up->notified = 0;
-
-	nureg = up->ureg;	/* pointer to user returned Ureg struct */
-
-	/* sanity clause */
 	oureg = (ulong)nureg;
-	if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
 
-	memmove(ureg, nureg, sizeof(Ureg));
+	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 
 	switch(arg0){
 	case NCONT:
 	case NRSTR:
-		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0))
+			return -1;
 		break;
-
 	case NSAVE:
 		if(!okaddr(nureg->pc, BY2WD, 0)
-		|| !okaddr(nureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		|| !okaddr(nureg->usp, BY2WD, 0))
+			return -1;
 		sp = oureg-4*BY2WD-ERRMAX;
-		splhi();
 		ureg->sp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-		
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
 	up->fpstate &= ~FPnotify;
 	if (up->fpstate == FPactive)
@@ -715,4 +648,5 @@
 		ureg->srr1 |= MSR_FP;
 	else
 		ureg->srr1 &= ~MSR_FP;
+	return 0;
 }
--- a/sys/src/9/sgi/trap.c
+++ b/sys/src/9/sgi/trap.c
@@ -258,7 +258,7 @@
 	splhi();
 
 	if(user){
-		notify(ur);
+		donotify(ur);
 		/* replicate fpstate to ureg status */
 		if(up->fpstate != FPactive)
 			ur->status &= ~CU1;
@@ -439,19 +439,19 @@
 }
 
 void
-fpunotify(void)
+fpunotify(Proc *p)
 {
-	if(up->fpstate == FPactive){
-		savefpregs(up->fpsave);
-		up->fpstate = FPinactive;
+	if(p->fpstate == FPactive){
+		savefpregs(p->fpsave);
+		p->fpstate = FPinactive;
 	}
-	up->fpstate |= FPnotify;
+	p->fpstate |= FPnotify;
 }
 
 void
-fpunoted(void)
+fpunoted(Proc *p)
 {
-	up->fpstate &= ~FPnotify;
+	p->fpstate &= ~FPnotify;
 }
 
 FPsave*
@@ -460,39 +460,20 @@
 	return nil;
 }
 
-int
-notify(Ureg *ur)
+Ureg*
+notify(Ureg *ur, char *msg)
 {
+	Ureg *nur;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ur);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ur->usp & ~(BY2V-1);
 	sp -= sizeof(Ureg);
 
-	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
-	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
-		pprint("suicide: bad address or sp in notify\n");
-		qunlock(&up->debug);
-		pexit("Suicide", 0);
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
 
-	memmove((Ureg*)sp, ur, sizeof(Ureg));	/* push user regs */
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nur = (Ureg*)sp;
+	memmove(nur, ur, sizeof(Ureg));	/* push user regs */
 
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);	/* push err string */
@@ -499,8 +480,8 @@
 
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
-	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
-	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
+	ur->r1 = (long)nur;			/* arg 1 is ureg* */
+	((ulong*)sp)[1] = (ulong)nur;		/* arg 1 0(FP) is ureg* */
 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
 	ur->usp = sp;
 	/*
@@ -509,40 +490,20 @@
 	 */
 	ur->pc = (ulong)up->notify;
 
-	splhi();
-	fpunotify();
-	qunlock(&up->debug);
-	return 1;
+	return nur;
 }
 
 /*
  * Return user to state before notify(); called from user's handler.
  */
-void
-noted(Ureg *kur, int arg0)
+int
+noted(Ureg *kur, Ureg *nur, int arg0)
 {
-	Ureg *nur;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted();
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nur = up->ureg;
 	oureg = (ulong)nur;
-	if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad up->ureg in noted or call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
+	if(oureg & (BY2WD-1))
+		return -1;
 
 	setregisters(kur, (char*)kur, (char*)nur, sizeof(Ureg));
 
@@ -549,39 +510,22 @@
 	switch(arg0) {
 	case NCONT:
 	case NRSTR:				/* only used by APE */
-		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0))
+			return -1;
 		break;
 
 	case NSAVE:				/* only used by APE */
 		sp = oureg-4*BY2WD-ERRMAX;
-		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(sp, 4*BY2WD, 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(sp, 4*BY2WD, 1))
+			return -1;
 		kur->r1 = oureg;		/* arg 1 is ureg* */
 		kur->usp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+
+	return 0;
 }
 
 /*
@@ -599,7 +543,7 @@
 	if(dosyscall(scallnr, (Sargs*)(ur->sp+BY2WD), &ur->r1) == 0)
 		ur->pc += 4;
 	if(up->procctl || up->nnote)
-		notify(ur);
+		donotify(ur);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
--- a/sys/src/9/teg2/fns.h
+++ b/sys/src/9/teg2/fns.h
@@ -144,8 +144,6 @@
 extern int fpudevprocio(Proc*, void*, long, uintptr, int);
 extern FPalloc *fpalloc(void);
 extern void fpuinit(void);
-extern void fpunoted(void);
-extern void fpunotify(void);
 extern void fpuprocrestore(Proc*);
 extern void fpuprocsave(Proc*);
 extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/teg2/trap.c
+++ b/sys/src/9/teg2/trap.c
@@ -172,8 +172,6 @@
 static ulong shadena[32];	/* copy of enable bits, saved by intcmaskall */
 static Lock distlock, nintrlock;
 
-extern int notify(Ureg*);
-
 static void dumpstackwithureg(Ureg *ureg);
 
 void
@@ -863,7 +861,7 @@
 
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
--- a/sys/src/9/xen/fns.h
+++ b/sys/src/9/xen/fns.h
@@ -15,9 +15,7 @@
 void	fpuprocfork(Proc*);
 void	fpuprocsave(Proc*);
 void	fpuprocrestore(Proc*);
-void	fpunotify(Proc*);
-void	fpunoted(Proc*);
-int		cpuidentify(void);
+int	cpuidentify(void);
 void	cpuidprint(void);
 void	(*cycles)(uvlong*);
 void	delay(int);
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -166,7 +166,7 @@
 
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 
@@ -359,7 +359,7 @@
 	scallnr = ureg->ax;
 	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->ax);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
@@ -370,84 +370,40 @@
  *  Call user, if necessary, with note.
  *  Pass user the Ureg struct and the note on his stack.
  */
-int
-notify(Ureg* ureg)
+Ureg*
+notify(Ureg* ureg, char *msg)
 {
+	Ureg *nureg;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->usp;
 	sp -= sizeof(Ureg);
 
-	if(!okaddr((ulong)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1))
+		return nil;
 
-	up->ureg = (void*)sp;
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
-	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
+	*(ulong*)(sp+1*BY2WD) = (ulong)nureg;		/* arg 1 is ureg* */
 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
 	ureg->usp = sp;
 	ureg->pc = (ulong)up->notify;
-	splhi();
-	fpunotify(up);
-	qunlock(&up->debug);
-	return 1;
+	return nureg;
 }
 
 /*
  *   Return user to state before notify()
  */
-void
-noted(Ureg* ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted(up);
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;	/* pointer to user returned Ureg struct */
-
-	/* sanity clause */
 	oureg = (ulong)nureg;
-	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
 
 	/*
 	 * Check the segment selectors are all valid, otherwise
@@ -459,14 +415,13 @@
 	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
 	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
 	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
+
 		pprint("bad segment selector in noted\n");
 		pprint("cs is %#lux, wanted %#ux\n", nureg->cs, UESEL);
 		pprint("ds is %#lux, wanted %#ux\n", nureg->ds, UDSEL);
 		pprint("es is %#lux, fs is %#lux, gs %#lux, wanted %#ux\n", 
 			ureg->es, ureg->fs, ureg->gs, UDSEL);
-		qunlock(&up->debug);
-		pprint("ss is %#lux, wanted %#ux\n", nureg->ss, UDSEL);
-		pexit("Suicide", 0);
+		return -1;
 	}
 
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
@@ -474,38 +429,19 @@
 	switch(arg0){
 	case NCONT:
 	case NRSTR:
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->usp, BY2WD, 0)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->usp, BY2WD, 0))
+			return -1;
 		break;
-
 	case NSAVE:
 		sp = oureg-4*BY2WD-ERRMAX;
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4*BY2WD, 1)){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, 1, 0) || !okaddr(sp, 4*BY2WD, 1))
+			return -1;
 		ureg->usp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
-
-	default:
-		up->lastnote->flag = NDebug;
-		/* fall through */
-		
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
+	return 0;
 }
 
 uintptr
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -201,7 +201,7 @@
 	splhi();
 	if(user){
 		if(up->procctl || up->nnote)
-			notify(ureg);
+			donotify(ureg);
 		kexit(ureg);
 	}
 }
@@ -216,39 +216,39 @@
 	scallnr = ureg->r0;
 	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
 	if(up->procctl || up->nnote)
-		notify(ureg);
+		donotify(ureg);
 	if(up->delaysched)
 		sched();
 	kexit(ureg);
 }
 
-static void
-fpunotify(void)
+void
+fpunotify(Proc *p)
 {
-	if(up->fpstate == FPactive){
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
+	if(p->fpstate == FPactive){
+		fpsave(p->fpsave);
+		p->fpstate = FPinactive;
 	}
-	up->fpstate |= FPnotify;
+	p->fpstate |= FPnotify;
 }
 
-static void
-fpunoted(void)
+void
+fpunoted(Proc *p)
 {
-	if(up->fpstate & FPnotify){
-		up->fpstate &= ~FPnotify;
+	if(p->fpstate & FPnotify){
+		p->fpstate &= ~FPnotify;
 	} else {
 		FPsave *o;
 
-		if(up->fpstate == FPactive)
+		if(p->fpstate == FPactive)
 			fpclear();
-		if((o = up->ofpsave) != nil) {
-			up->ofpsave = nil;
-			fpfree(up->fpsave);
-			up->fpsave = o;
-			up->fpstate = FPinactive;
+		if((o = p->ofpsave) != nil) {
+			p->ofpsave = nil;
+			fpfree(p->fpsave);
+			p->fpsave = o;
+			p->fpstate = FPinactive;
 		} else {
-			up->fpstate = FPinit;
+			p->fpstate = FPinit;
 		}
 	}
 }
@@ -264,121 +264,68 @@
 	return p->ofpsave;
 }
 
-int
-notify(Ureg *ureg)
+Ureg*
+notify(Ureg *ureg, char *msg)
 {
+	Ureg *nureg;
 	ulong sp;
-	char *msg;
 
-	if(up->procctl)
-		procctl();
-	if(up->nnote == 0)
-		return 0;
-
-	spllo();
-	qlock(&up->debug);
-	msg = popnote(ureg);
-	if(msg == nil){
-		qunlock(&up->debug);
-		splhi();
-		return 0;
-	}
-
 	sp = ureg->sp;
 	sp -= 256;	/* debugging: preserve context causing problem */
 	sp -= sizeof(Ureg);
 
-	if(!okaddr((uintptr)up->notify, 1, 0)
-	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+	if(!okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
 	|| ((uintptr) up->notify & 3) != 0
-	|| (sp & 3) != 0){
-		qunlock(&up->debug);
-		pprint("suicide: bad address in notify\n");
-		pexit("Suicide", 0);
-	}
+	|| (sp & 3) != 0)
+		return nil;
 
-	memmove((Ureg*)sp, ureg, sizeof(Ureg));
-	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
-	up->ureg = (void*)sp;
+	nureg = (Ureg*)sp;
+	memmove(nureg, ureg, sizeof(Ureg));
 	sp -= BY2WD+ERRMAX;
 	memmove((char*)sp, msg, ERRMAX);
 	sp -= 3*BY2WD;
 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
-	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
-	ureg->r0 = (uintptr) up->ureg;
+	*(ulong*)(sp+1*BY2WD) = (ulong)nureg;
+	ureg->r0 = (uintptr)nureg;
 	ureg->sp = sp;
-	ureg->pc = (uintptr) up->notify;
+	ureg->pc = (uintptr)up->notify;
 	ureg->r14 = 0;
 
-	splhi();
-	fpunotify();
-	qunlock(&up->debug);
-	return 1;
+	return nureg;
 }
 
-void
-noted(Ureg *ureg, int arg0)
+int
+noted(Ureg *ureg, Ureg *nureg, int arg0)
 {
-	Ureg *nureg;
 	ulong oureg, sp;
 	
-	qlock(&up->debug);
-	if(up->notified){
-		up->notified = 0;
-		splhi();
-		fpunoted();
-		spllo();
-	} else if(arg0!=NRSTR){
-		qunlock(&up->debug);
-		pprint("call to noted() when not notified\n");
-		pexit("Suicide", 0);
-	}
-
-	nureg = up->ureg;	
 	oureg = (ulong) nureg;
-	if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
-		qunlock(&up->debug);
-		pprint("bad ureg in noted or call to noted when not notified\n");
-		pexit("Suicide", 0);
-	}
+	if((oureg & 3) != 0)
+		return -1;
 
 	setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
 	
 	switch(arg0){
 	case NCONT: case NRSTR:
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(ureg->sp, BY2WD, 0) ||
-				(ureg->pc & 3) != 0 || (ureg->sp & 3) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(ureg->sp, BY2WD, 0)
+		|| (ureg->pc & 3) != 0 || (ureg->sp & 3) != 0)
+			return -1;
 		break;
 	
 	case NSAVE:
 		sp = oureg - 4 * BY2WD - ERRMAX;
-		if(!okaddr(ureg->pc, BY2WD, 0) || !okaddr(sp, 4 * BY2WD, 1) || (ureg->pc & 3) != 0 || (sp & 3) != 0){
-			qunlock(&up->debug);
-			pprint("suicide: trap in noted\n");
-			pexit("Suicide", 0);
-		}
-		qunlock(&up->debug);
+		if(!okaddr(ureg->pc, BY2WD, 0)
+		|| !okaddr(sp, 4 * BY2WD, 1)
+		|| (ureg->pc & 3) != 0 || (sp & 3) != 0)
+			return -1;
 		ureg->sp = sp;
 		ureg->r0 = (uintptr) oureg;
 		((ulong *) sp)[1] = oureg;
 		((ulong *) sp)[0] = 0;
 		break;
-	
-	default:
-		up->lastnote->flag = NDebug;
-	
-	case NDFLT:
-		qunlock(&up->debug);
-		if(up->lastnote->flag == NDebug)
-			pprint("suicide: %s\n", up->lastnote->msg);
-		pexit(up->lastnote->msg, up->lastnote->flag != NDebug);
 	}
+	return 0;
 }
 
 
--