shithub: riscv

Download patch

ref: 6253af7a5ce9ed1f223769b1d690b9f6beca6850
parent: ba59008e1da6bdf87648f9cc44aac83095c49600
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Apr 15 20:26:01 EDT 2025

kernel: refactor syscall and note handling

The differences between the syscall handlers are just
the scallnr register, return register and the address
where we fetch the stack arguments.

So provide a dosyscall() function where we pass the
syscall number, the Sargs* pointer and a uintptr*
for the return value.

The sysnoted() call is a bit special, as it needs
all the registers to be restoed. For this dosyscall()
returns a integer status. When 1, full register
restore is needed.

Also, it was determined that the Sargs* pointer needs
to be alignment checked (now using evenaddr()).

Now all kernels support ratrace syscall tracing.

--- a/sys/src/9/arm64/fns.h
+++ b/sys/src/9/arm64/fns.h
@@ -110,7 +110,6 @@
 extern void procrestore(Proc *);
 extern void trap(Ureg*);
 extern void syscall(Ureg*);
-extern void noted(Ureg*, ulong);
 extern void faultarm64(Ureg*);
 extern void dumpstack(void);
 extern void dumpregs(Ureg*);
--- a/sys/src/9/arm64/trap.c
+++ b/sys/src/9/arm64/trap.c
@@ -4,7 +4,6 @@
 #include "dat.h"
 #include "fns.h"
 #include "../port/error.h"
-#include "../port/systab.h"
 
 #include <tos.h>
 #include "ureg.h"
@@ -187,87 +186,17 @@
 void
 syscall(Ureg *ureg)
 {
-	vlong startns, stopns;
-	uintptr sp, ret;
 	ulong scallnr;
-	int i, s;
-	char *e;
 
 	if(!kenter(ureg))
 		panic("syscall from  kernel");
 	fpukenter(ureg);
 	
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-	
-	sp = ureg->sp;
-	up->scallnr = scallnr = ureg->r0;
-	spllo();
-	
-	startns = 0;
-	ret = -1;
-	if(!waserror()){
-		if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-			evenaddr(sp);
-		}
-		up->s = *((Sargs*) (sp + BY2WD));
-
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-		
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-	ureg->r0 = ret;
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	if(scallnr == NOTED){
-		noted(ureg, *((ulong*) up->s.args));
-		/*
-		 * normally, syscall() returns to forkret()
-		 * not restoring general registers when going
-		 * to userspace. to completely restore the
-		 * interrupted context, we have to return thru
-		 * noteret(). we override return pc to jump to
-		 * to it when returning form syscall()
-		 */
+	scallnr = ureg->r0;
+	if(dosyscall(scallnr, (Sargs*)(ureg->sp+BY2WD), &ureg->r0))
 		returnto(noteret);
-	}
 
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote))
+	if(up->procctl || up->nnote)
 		notify(ureg);
 
 	if(up->delaysched)
@@ -333,7 +262,7 @@
 }
 
 void
-noted(Ureg *ureg, ulong arg0)
+noted(Ureg *ureg, int arg0)
 {
 	Ureg *nureg;
 	uintptr oureg, sp;
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -109,7 +109,6 @@
 extern void procrestore(Proc *);
 extern void trap(Ureg*);
 extern void syscall(Ureg*);
-extern void noted(Ureg*, ulong);
 extern void faultarm64(Ureg*);
 extern void dumpstack(void);
 extern void dumpregs(Ureg*);
--- a/sys/src/9/cycv/fns.h
+++ b/sys/src/9/cycv/fns.h
@@ -44,7 +44,6 @@
 void setasid(ulong);
 void flushtlb(void);
 void touser(void *);
-void noted(Ureg *, ulong);
 void l1switch(L1 *, int);
 void intrenable(int, void (*)(Ureg *, void *), void *, int, char *);
 void intrinit(void);
--- a/sys/src/9/cycv/trap.c
+++ b/sys/src/9/cycv/trap.c
@@ -195,83 +195,16 @@
 	}
 }
 
-#include "../port/systab.h"
-
 void
 syscall(Ureg *ureg)
 {
-	char *e;
-	uintptr sp;
-	long ret;
-	int i, s;
 	ulong scallnr;
-	vlong startns, stopns;
 	
 	if(!kenter(ureg))
 		panic("syscall: pc=%#.8lux", ureg->pc);
-	
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-	
-	sp = ureg->sp;
-	up->scallnr = scallnr = ureg->r0;
-
-	spllo();
-	
-	ret = -1;
-	if(!waserror()){
-		if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-			evenaddr(sp);
-		}
-		up->s = *((Sargs*) (sp + BY2WD));
-		
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-		
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-	
-	ureg->r0 = ret;
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-	
-	up->insyscall = 0;
-	up->psstate = 0;
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong *) up->s.args));
-
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote))
+	scallnr = ureg->r0;
+	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
+	if(up->procctl || up->nnote)
 		notify(ureg);
 	if(up->delaysched)
 		sched();
@@ -353,7 +286,7 @@
 }
 
 void
-noted(Ureg *ureg, ulong arg0)
+noted(Ureg *ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -112,7 +112,6 @@
 extern void procrestore(Proc *);
 extern void trap(Ureg*);
 extern void syscall(Ureg*);
-extern void noted(Ureg*, ulong);
 extern void faultarm64(Ureg*);
 extern void dumpstack(void);
 extern void dumpregs(Ureg*);
--- a/sys/src/9/lx2k/fns.h
+++ b/sys/src/9/lx2k/fns.h
@@ -112,7 +112,6 @@
 extern void procrestore(Proc *);
 extern void trap(Ureg*);
 extern void syscall(Ureg*);
-extern void noted(Ureg*, ulong);
 extern void faultarm64(Ureg*);
 extern void dumpstack(void);
 extern void dumpregs(Ureg*);
--- a/sys/src/9/mt7688/fns.h
+++ b/sys/src/9/mt7688/fns.h
@@ -85,8 +85,6 @@
 ulong	getconfig7(void);
 ulong	gethwreg3(void);
 void	plan9iniinit(void);
-void	noted(Ureg*, ulong);
-int		notify(Ureg*);
 void	intrinit(void);
 int		i8250console(void);
 void	setconfenv(void);
--- a/sys/src/9/mt7688/syscall.c
+++ b/sys/src/9/mt7688/syscall.c
@@ -4,7 +4,6 @@
 #include "dat.h"
 #include "fns.h"
 #include "../port/error.h"
-#include "../port/systab.h"
 
 #include "tos.h"
 #include "ureg.h"
@@ -11,111 +10,27 @@
 
 FPsave initfp;
 
-
 /*
  * called directly from assembler, not via trap()
  */
 void
-syscall(Ureg* ureg)
+syscall(Ureg *ur)
 {
-	char *e;
-	u32int s;
-	ulong sp;
-	long ret;
-	int i;
-	vlong startns, stopns;
 	ulong scallnr;
 
-	if(!kenter(ureg))
+	if(!kenter(ur))
 		panic("syscall from kernel");
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
-	scallnr = ureg->r1;
-	up->scallnr = ureg->r1;
-	spllo();
-	sp = ureg->sp;
-
-	up->nerrlab = 0;
-	ret = -1;
-
-	if(!waserror()){
-		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)))
-			validaddr(sp, sizeof(Sargs), 0);
-
-		up->s = *((Sargs*)(sp));	/* spim's libc is different to mips ... */
-
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-//		iprint("[%lud %s] syscall %lud: %s\n",up->pid, up->text, scallnr, up->errstr);
-	}
-
-	if(up->nerrlab){
-		iprint("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			iprint("sp=%#p pc=%#p\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->pc += 4;
-	ureg->r1 = ret;
-
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong*)up->s.args));
-
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote))
-		notify(ureg);
-
+	scallnr = ur->r1;
+	if(dosyscall(scallnr, (Sargs*)ur->sp, &ur->r1) == 0)
+		ur->pc += 4;
+	if(up->procctl || up->nnote)
+		notify(ur);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
-
-	kexit(ureg);
-
+	kexit(ur);
 	/* restore EXL in status */
 	setstatus(getstatus() | EXL);
-
 }
 
 void
@@ -131,7 +46,7 @@
 }
 
 FPsave*
-notefpsave(Proc *p)
+notefpsave(Proc*)
 {
 	return nil;
 }
@@ -195,7 +110,7 @@
  * Return user to state before notify(); called from user's handler.
  */
 void
-noted(Ureg *kur, ulong arg0)
+noted(Ureg *kur, int arg0)
 {
 	Ureg *nur;
 	ulong oureg, sp;
@@ -214,8 +129,8 @@
 
 	oureg = (ulong)nur;
 	if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		pprint("bad up->ureg in noted or call to noted() when not notified\n");
 		qunlock(&up->debug);
+		pprint("bad up->ureg in noted or call to noted() when not notified\n");
 		pexit("Suicide", 0);
 	}
 
@@ -225,8 +140,8 @@
 	case NCONT:
 	case NRSTR:				/* only used by APE */
 		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0)){
-			pprint("suicide: trap in noted\n");
 			qunlock(&up->debug);
+			pprint("suicide: trap in noted\n");
 			pexit("Suicide", 0);
 		}
 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
@@ -238,8 +153,8 @@
 		kur->r1 = oureg;		/* arg 1 is ureg* */
 		kur->usp = sp;
 		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, 4*BY2WD, 1)){
-			pprint("suicide: trap in noted\n");
 			qunlock(&up->debug);
+			pprint("suicide: trap in noted\n");
 			pexit("Suicide", 0);
 		}
 		qunlock(&up->debug);
@@ -248,14 +163,13 @@
 		break;
 
 	default:
-		pprint("unknown noted arg %#lux\n", arg0);
 		up->lastnote->flag = NDebug;
 		/* fall through */
 
 	case NDFLT:
+		qunlock(&up->debug);
 		if(up->lastnote->flag == NDebug)
 			pprint("suicide: %s\n", up->lastnote->msg);
-		qunlock(&up->debug);
 		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
 }
--- a/sys/src/9/mt7688/trap.c
+++ b/sys/src/9/mt7688/trap.c
@@ -14,7 +14,6 @@
 
 int	intr(Ureg*);
 void	kernfault(Ureg*, int);
-void	noted(Ureg*, ulong);
 void	rfnote(Ureg**);
 
 char *excname[] =
--- a/sys/src/9/mtx/trap.c
+++ b/sys/src/9/mtx/trap.c
@@ -5,6 +5,7 @@
 #include	"fns.h"
 #include	"ureg.h"
 #include	"io.h"
+#include	"../port/pci.h"
 #include	"tos.h"
 #include	"../port/error.h"
 
@@ -145,7 +146,6 @@
 }
 
 void	syscall(Ureg*);
-void	noted(Ureg*, ulong);
 static void _dumpstack(Ureg*);
 
 char *excname[] =
@@ -374,10 +374,8 @@
 		mpiceoi(0);
 	}
 
-	if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
+	if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0)
 		panic("spurious intr %d", vno);
-		return;
-	}
 
 	if(ctl->isr)
 		ctl->isr(vno);
@@ -590,73 +588,34 @@
 /*
  *  system calls
  */
-#include "../port/systab.h"
 
 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
 void
 syscall(Ureg* ureg)
 {
-	int i;
-	char *e;
-	long	ret;
-	ulong sp, scallnr;
+	ulong scallnr;
 
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
-	scallnr = ureg->r3;
-	up->scallnr = ureg->r3;
-	spllo();
-
-	sp = ureg->usp;
-	ret = -1;
-	if(!waserror()){
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr](up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
+	if(!kenter(ureg))
+		panic("syscall from kernel");
+	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
+		print("fpstate check, entry syscall\n");
+		delay(200);
+		dumpregs(ureg);
+		print("fpstate check, entry syscall\n");
 	}
-	if(up->nerrlab){
-		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
-		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->r3 = ret;
-
-	if(scallnr == NOTED)
-		noted(ureg, *(ulong*)(sp+BY2WD));
-
-	/* restoreureg must execute at high IPL */
-	splhi();
-	if(scallnr!=RFORK)
+	scallnr = ureg->r3;
+	dosyscall(scallnr, (Sargs*)(ureg->usp+BY2WD), &ureg->r3);
+	if(up->procctl || up->nnote)
 		notify(ureg);
-	if(up->fpstate == FPinactive)
+	/* if we delayed sched because we held a lock, sched now */
+	if(up->delaysched)
+		sched();
+	kexit(ureg);
+	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
+		print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
+		dumpregs(ureg);
+	}
+	if(up->fpstate != FPactive)
 		ureg->srr1 &= ~MSR_FP;
 }
 
@@ -716,7 +675,7 @@
  *   Return user to state before notify()
  */
 void
-noted(Ureg* ureg, ulong arg0)
+noted(Ureg* ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
--- a/sys/src/9/omap/syscall.c
+++ b/sys/src/9/omap/syscall.c
@@ -4,7 +4,6 @@
 #include "dat.h"
 #include "fns.h"
 #include "../port/error.h"
-#include "../port/systab.h"
 
 #include <tos.h>
 #include "ureg.h"
@@ -23,8 +22,8 @@
 /*
  *   Return user to state before notify()
  */
-static void
-noted(Ureg* cur, uintptr arg0)
+void
+noted(Ureg* cur, int arg0)
 {
 	NFrame *nf;
 
@@ -147,88 +146,15 @@
 void
 syscall(Ureg* ureg)
 {
-	char *e;
-	u32int s;
-	ulong sp;
-	long ret;
-	int i, scallnr;
-	vlong startns, stopns;
+	ulong scallnr;
 
 	if(!kenter(ureg))
 		panic("syscall: from kernel: pc %#lux r14 %#lux psr %#lux",
 			ureg->pc, ureg->r14, ureg->psr);
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
 	scallnr = ureg->r0;
-	up->scallnr = scallnr;
-	spllo();
-	sp = ureg->sp;
-
-	up->nerrlab = 0;
-	ret = -1;
-	if(!waserror()){
-		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-		up->s = *((Sargs*)(sp+BY2WD));
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-	if(up->nerrlab){
-		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%#p pc=%#p\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->r0 = ret;
-
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong*)up->s.args));
-
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote))
+	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
+	if(up->procctl || up->nnote)
 		notify(ureg);
-
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -12,8 +12,6 @@
 extern int irqhandled(Ureg*, int);
 extern void irqinit(void);
 
-void	noted(Ureg*, ulong);
-
 static void debugexc(Ureg*, void*);
 static void debugbpt(Ureg*, void*);
 static void fault386(Ureg*, void*);
@@ -450,100 +448,18 @@
 }
 
 /*
- *  system calls
- */
-#include "../port/systab.h"
-
-/*
  *  Syscall is called directly from assembler without going through trap().
  */
 void
 syscall(Ureg* ureg)
 {
-	char *e;
-	ulong	sp;
-	long	ret;
-	int	i, s;
 	ulong scallnr;
-	vlong startns, stopns;
 
 	if(!kenter(ureg))
 		panic("syscall: cs 0x%4.4luX", ureg->cs);
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
-	sp = ureg->usp;
 	scallnr = ureg->ax;
-	up->scallnr = scallnr;
-
-	spllo();
-
-	ret = -1;
-	if(!waserror()){
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-		if(0 && up->pid == 1)
-			print("syscall %lud error %s\n", scallnr, up->syserrstr);
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->ax = ret;
-
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong*)up->s.args));
-
-	splhi();
-	if(scallnr!=RFORK && (up->procctl || up->nnote))
+	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->ax);
+	if(up->procctl || up->nnote)
 		notify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
@@ -612,7 +528,7 @@
  *   Return user to state before notify()
  */
 void
-noted(Ureg* ureg, ulong arg0)
+noted(Ureg* ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -12,8 +12,6 @@
 extern int irqhandled(Ureg*, int);
 extern void irqinit(void);
 
-void	noted(Ureg*, ulong);
-
 static void debugexc(Ureg*, void*);
 static void debugbpt(Ureg*, void*);
 static void faultamd64(Ureg*, void*);
@@ -427,118 +425,24 @@
 }
 
 /*
- *  system calls
- */
-#include "../port/systab.h"
-
-/*
  *  Syscall is called directly from assembler without going through trap().
  */
 void
 syscall(Ureg* ureg)
 {
-	char *e;
-	uintptr	sp;
-	long long ret;
-	int i, s;
 	ulong scallnr;
-	vlong startns, stopns;
 
 	if(!kenter(ureg))
 		panic("syscall: cs 0x%4.4lluX", ureg->cs);
 	fpukenter(ureg);
-
-	m->syscall++;
-	up->insyscall = 1;
-
-	up->pc = ureg->pc;
-	sp = ureg->sp;
 	scallnr = ureg->bp;	/* RARG */
-	up->scallnr = scallnr;
-	spllo();
-
-	ret = -1;
-	startns = 0;
-	if(!waserror()){
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-		if(0){
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			print("syscall: %s\n", up->syscalltrace);
-		}
-
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-		if(0 && up->pid == 1)
-			print("syscall %lud error %s\n", scallnr, up->syserrstr);
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%#p pc=%#p\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-	ureg->ax = ret;
-
-	if(0){
-		print("syscallret: %lud %s %s ret=%lld\n", 
-			up->pid, up->text, sysctab[scallnr], ret);
-	}
-
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	if(scallnr == NOTED){
-		/*
-		 * normally, syscall() returns to forkret()
-		 * not restoring general registers when going
-		 * to userspace. to completely restore the
-		 * interrupted context, we have to return thru
-		 * noteret(). we override return pc to jump to
-		 * to it when returning form syscall()
-		 */
-		((void**)&ureg)[-1] = (void*)noteret;
-		noted(ureg, *((ulong*)up->s.args));
-	}
-
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote) && notify(ureg))
+	if(dosyscall(scallnr, (Sargs*)(ureg->sp+BY2WD), &ureg->ax))
 		((void**)&ureg)[-1] = (void*)noteret;	/* loads RARG */
-
-	up->insyscall = 0;
-	up->psstate = nil;
-
+	if((up->procctl || up->nnote) && notify(ureg))
+		((void**)&ureg)[-1] = (void*)noteret;	/* loads RARG */
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
-
 	kexit(ureg);
 	fpukexit(ureg);
 }
@@ -606,7 +510,7 @@
  *   Return user to state before notify()
  */
 void
-noted(Ureg* ureg, ulong arg0)
+noted(Ureg* ureg, int arg0)
 {
 	Ureg *nureg;
 	uintptr oureg, sp;
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -726,7 +726,6 @@
 	int	noswap;		/* process is not swappable */
 	int	hang;		/* hang at next exec for debug */
 	int	procctl;	/* Control for /proc debugging */
-	uintptr	pc;		/* DEBUG only */
 
 	Lock	rlock;		/* sync sleep/wakeup with procinterrupt */
 	Rendez	*r;		/* rendezvous point slept on */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -80,6 +80,7 @@
 Walkqid*	devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
 int		devwstat(Chan*, uchar*, int);
 Dir*		dirchanstat(Chan *);
+int		dosyscall(ulong, Sargs*, uintptr*);
 void		drawactive(int);
 void		drawcmap(void);
 void		dtracytick(Ureg*);
@@ -221,6 +222,7 @@
 Proc*		newproc(void);
 _Noreturn void	nexterror(void);
 int		notify(Ureg*);
+void		noted(Ureg*, int);
 FPsave*		notefpsave(Proc*);
 ulong		nkpages(Confmem*);
 uvlong		ns2fastticks(uvlong);
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -112,8 +112,8 @@
 random.$O:	/sys/include/libsec.h
 wifi.$O:	/sys/include/libsec.h 
 devaoe.$O sdaoe.$O:	/sys/include/fis.h
-sysproc.$O:	/sys/include/a.out.h
-syscallfmt.$O:	/sys/src/libc/9syscall/sys.h
+sysproc.$O:	/sys/include/a.out.h ../port/systab.h
+sysproc.$O syscallfmt.$O:	/sys/src/libc/9syscall/sys.h
 devusb.$O usbxhci.$O usbxhcipci.$O:	../port/usb.h
 usbxhci.$O usbxhcipci.$O:	../port/usbxhci.h
 devether.$O: ../ip/ip.h ../ip/ipv6.h
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -782,8 +782,12 @@
 uintptr
 sysnoted(va_list list)
 {
-	if(va_arg(list, int) != NRSTR && !up->notified)
+	int arg;
+
+	arg = va_arg(list, int);
+	if(arg != NRSTR && !up->notified)
 		error(Egreg);
+	noted(up->dbgreg, arg);
 	return 0;
 }
 
@@ -1264,5 +1268,77 @@
 	evenaddr((uintptr)v);
 	validaddr((uintptr)v, sizeof(vlong), 1);
 	*v = todget(nil, nil);
+	return 0;
+}
+
+#include "../port/systab.h"
+
+int
+dosyscall(ulong scallnr, Sargs *args, uintptr *retp)
+{
+	vlong startns, stopns;
+	uintptr ret;
+	int s;
+
+	m->syscall++;
+
+	up->insyscall = 1;
+	s = spllo();
+
+	if(!waserror()){
+		evenaddr((uintptr)args);
+		validaddr((uintptr)args, sizeof(Sargs), 0);
+
+		up->s = *args;
+		up->scallnr = scallnr;
+
+		if(up->procctl == Proc_tracesyscall){
+			syscallfmt(scallnr, userpc(), (va_list)up->s.args);
+			splhi();
+			up->procctl = Proc_stopme;
+			procctl();
+			spllo();
+			todget(nil, &startns);
+		}
+		if(scallnr >= nsyscall || systab[scallnr] == nil){
+			postnote(up, 1, "sys: bad sys call", NDebug);
+			error(Ebadarg);
+		}
+		up->psstate = sysctab[scallnr];
+		ret = systab[scallnr]((va_list)up->s.args);			
+		poperror();
+		if(scallnr == NOTED){
+			/* special case: noted() changes the ureg, return without setting *retp */
+			splx(s);
+			up->insyscall = 0;
+			up->psstate = nil;
+			return 1;
+		}
+	}else{
+		/* failure: save the error buffer for errstr */
+		char *e = up->syserrstr;
+		up->syserrstr = up->errstr;
+		up->errstr = e;
+		ret = -1;
+	}
+	if(up->nerrlab){
+		int i;
+
+		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
+		for(i = 0; i < NERR; i++)
+			print("sp=%#p pc=%#p\n", up->errlab[i].sp, up->errlab[i].pc);
+		panic("error stack");
+	}
+	*retp = ret;
+	if(up->procctl == Proc_tracesyscall){
+		todget(nil, &stopns);
+		sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
+		splhi();
+		up->procctl = Proc_stopme;
+		procctl();
+	}
+	splx(s);
+	up->insyscall = 0;
+	up->psstate = nil;
 	return 0;
 }
--- a/sys/src/9/ppc/dat.h
+++ b/sys/src/9/ppc/dat.h
@@ -75,7 +75,7 @@
 	FPactive = 1,
 	FPinactive = 2,
 	/* Bit that's or-ed in during note handling (FP is illegal in note handlers) */
-	FPillegal = 0x100,
+	FPnotify = 0x100,
 };
 
 struct Confmem
--- a/sys/src/9/ppc/main.c
+++ b/sys/src/9/ppc/main.c
@@ -189,12 +189,12 @@
 }
 
 void
-procfork(Proc *p)
+procfork(Proc*)
 {
 }
 
 void
-procrestore(Proc *p)
+procrestore(Proc*)
 {
 }
 
--- a/sys/src/9/ppc/trap.c
+++ b/sys/src/9/ppc/trap.c
@@ -73,7 +73,6 @@
 }
 
 void	syscall(Ureg*);
-void	noted(Ureg*, ulong);
 static void _dumpstack(Ureg*);
 
 char *excname[] =
@@ -148,9 +147,9 @@
 	extern FPsave initfp;
 
 	user = kenter(ureg);
+	ecode = (ureg->cause >> 8) & 0xff;
 	if((ureg->status & MSR_RI) == 0)
 		print("double fault?: ecode = %d\n", ecode);
-	ecode = (ureg->cause >> 8) & 0xff;
 	switch(ecode) {
 	case CEI:
 		m->intr++;
@@ -565,21 +564,15 @@
 /*
  *  system calls
  */
-#include "../port/systab.h"
 
 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
 void
 syscall(Ureg* ureg)
 {
-	int i;
-	char *e;
-	long	ret;
-	ulong sp, scallnr;
+	ulong scallnr;
 
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
+	if(!kenter(ureg))
+		panic("syscall from kernel");
 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
 		print("fpstate check, entry syscall\n");
 		delay(200);
@@ -586,58 +579,14 @@
 		dumpregs(ureg);
 		print("fpstate check, entry syscall\n");
 	}
-
 	scallnr = ureg->r3;
-	up->scallnr = ureg->r3;
-	spllo();
-
-	sp = ureg->usp;
-	ret = -1;
-	if(!waserror()){
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-	if(up->nerrlab){
-		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
-		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->r3 = ret;
-
-	if(scallnr == NOTED)
-		noted(ureg, *(ulong*)(sp+BY2WD));
-
-	/* restoreureg must execute at high IPL */
-	splhi();
-	if(scallnr!=RFORK)
+	dosyscall(scallnr, (Sargs*)(ureg->usp+BY2WD), &ureg->r3);
+	if(up->procctl || up->nnote)
 		notify(ureg);
-
+	/* if we delayed sched because we held a lock, sched now */
+	if(up->delaysched)
+		sched();
+	kexit(ureg);
 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
 		print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
 		dumpregs(ureg);
@@ -665,7 +614,7 @@
 		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
-	up->fpstate |= FPillegal;
+	up->fpstate |= FPnotify;
 
 	s = spllo();
 	qlock(&up->debug);
@@ -708,7 +657,7 @@
  *   Return user to state before notify()
  */
 void
-noted(Ureg* ureg, ulong arg0)
+noted(Ureg* ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
@@ -770,7 +719,7 @@
 			pprint("suicide: %s\n", up->lastnote->msg);
 		pexit(up->lastnote->msg, up->lastnote->flag!=NDebug);
 	}
-	up->fpstate &= ~FPillegal;
+	up->fpstate &= ~FPnotify;
 	if (up->fpstate == FPactive)
 		ureg->srr1 |= MSR_FP;
 	else
--- a/sys/src/9/sgi/trap.c
+++ b/sys/src/9/sgi/trap.c
@@ -21,7 +21,6 @@
 
 int	intr(Ureg*);
 void	kernfault(Ureg*, int);
-void	noted(Ureg*, ulong);
 void	rfnote(Ureg**);
 
 char *excname[] =
@@ -523,7 +522,7 @@
  * Return user to state before notify(); called from user's handler.
  */
 void
-noted(Ureg *kur, ulong arg0)
+noted(Ureg *kur, int arg0)
 {
 	Ureg *nur;
 	ulong oureg, sp;
@@ -543,8 +542,8 @@
 	nur = up->ureg;
 	oureg = (ulong)nur;
 	if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		pprint("bad up->ureg in noted or call to noted() when not notified\n");
 		qunlock(&up->debug);
+		pprint("bad up->ureg in noted or call to noted() when not notified\n");
 		pexit("Suicide", 0);
 	}
 
@@ -554,8 +553,8 @@
 	case NCONT:
 	case NRSTR:				/* only used by APE */
 		if(!okaddr(kur->pc, BY2WD, 0) || !okaddr(kur->usp, BY2WD, 0)){
-			pprint("suicide: trap in noted\n");
 			qunlock(&up->debug);
+			pprint("suicide: trap in noted\n");
 			pexit("Suicide", 0);
 		}
 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
@@ -564,20 +563,19 @@
 
 	case NSAVE:				/* only used by APE */
 		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)){
-			pprint("suicide: trap in noted\n");
+		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);
+		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:
-		pprint("unknown noted arg %#lux\n", arg0);
 		up->lastnote->flag = NDebug;
 		/* fall through */
 
@@ -589,52 +587,6 @@
 	}
 }
 
-#include "../port/systab.h"
-
-static void
-sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
-{
-	if(up->procctl == Proc_tracesyscall){
-		/*
-		 * Redundant validaddr.  Do we care?
-		 * Tracing syscalls is not exactly a fast path...
-		 * Beware, validaddr currently does a pexit rather
-		 * than an error if there's a problem; that might
-		 * change in the future.
-		 */
-		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
-		up->procctl = Proc_stopme;
-		procctl();
-		if(up->syscalltrace)
-			free(up->syscalltrace);
-		up->syscalltrace = nil;
-		todget(nil, startnsp);
-	}
-}
-
-static void
-sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
-{
-	vlong stopns;
-	int s;
-
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		up->procctl = Proc_stopme;
-		sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
-			startns, stopns);
-		s = splhi();
-		procctl();
-		splx(s);
-		if(up->syscalltrace)
-			free(up->syscalltrace);
-		up->syscalltrace = nil;
-	}
-}
-
 /*
  * called directly from assembler, not via trap()
  */
@@ -641,75 +593,15 @@
 void
 syscall(Ureg *ur)
 {
-	int i;
-	volatile long ret;
-	ulong sp, scallnr;
-	vlong startns;
-	char *e;
+	ulong scallnr;
 
 	if(!kenter(ur))
 		panic("syscall from kernel");
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ur->pc;
 	ur->cause = 16<<2;	/* for debugging: system call is undef 16 */
-
 	scallnr = ur->r1;
-	up->scallnr = ur->r1;
-	sp = ur->sp;
-	sctracesetup(scallnr, sp, ur->pc, &startns);
-
-	/* no fpu, so no fp state to save */
-	spllo();
-
-	ret = -1;
-	if(!waserror()) {
-		if(sp & (BY2WD-1)){
-			postnote(up, 1, "sys: odd stack", NDebug);
-			error(Ebadarg);
-		}
-
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-		if(0 && up->pid == 1)
-			print("[%lud %s] syscall %lud: %s\n",
-				up->pid, up->text, scallnr, up->errstr);
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%#lux pc=%#lux\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-	sctracefinish(scallnr, sp, ret, startns);
-
-	ur->pc += 4;
-	ur->r1 = ret;
-
-	up->psstate = 0;
-	up->insyscall = 0;
-
-	if(scallnr == NOTED)				/* ugly hack */
-		noted(ur, *(ulong*)(sp+BY2WD));	/* may return */
-	splhi();
-	if(scallnr!=RFORK && (up->procctl || up->nnote))
+	if(dosyscall(scallnr, (Sargs*)(ur->sp+BY2WD), &ur->r1) == 0)
+		ur->pc += 4;
+	if(up->procctl || up->nnote)
 		notify(ur);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
--- a/sys/src/9/xen/mkfile
+++ b/sys/src/9/xen/mkfile
@@ -33,6 +33,7 @@
 	qlock.$O\
 	rebootcmd.$O\
 	segment.$O\
+	syscallfmt.$O\
 	sysfile.$O\
 	sysproc.$O\
 	taslock.$O\
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -25,8 +25,6 @@
 	SPL3 = 3,
 	EvDisable = 4,
 };
-  
-void	noted(Ureg*, ulong);
 
 extern void irqinit(void);
 extern int irqhandled(Ureg*, int);
@@ -361,105 +359,22 @@
 }
 
 /*
- *  system calls
- */
-#include "../port/systab.h"
-
-/*
  *  Syscall is called directly from assembler without going through trap().
  */
 void
 syscall(Ureg* ureg)
 {
-	char *e;
-	ulong	sp;
-	long	ret;
-	int	i, s;
 	ulong scallnr;
 
-	SYSCALLLOG(dprint("%d: syscall ...#%ld(%s)\n", 
-			up->pid, ureg->ax, sysctab[ureg->ax]);)
-	
 	if(!kenter(ureg))
-		panic("syscall: cs 0x%4.4luX\n", ureg->cs);
-
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-
-	if(up->procctl == Proc_tracesyscall){
-		up->procctl = Proc_stopme;
-		procctl();
-	}
-
+		panic("syscall: cs 0x%4.4luX", ureg->cs);
 	scallnr = ureg->ax;
-	up->scallnr = scallnr;
-	if(scallnr == RFORK && up->fpstate == FPactive){
-		fpsave(up->fpsave);
-		up->fpstate = FPinactive;
-	}
-	spllo();
-
-	sp = ureg->usp;
-	ret = -1;
-	if(!waserror()){
-		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-
-		up->s = *((Sargs*)(sp+BY2WD));
-
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		/* failure: save the error buffer for errstr */
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-		if(0 && up->pid == 1)
-			print("syscall %lud error %s\n", scallnr, up->syserrstr);
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n",
-				up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-
-	SYSCALLLOG(dprint("%d: Syscall %d returns %d, ureg %p\n", up->pid, scallnr, ret, ureg);)
-	/*
-	 *  Put return value in frame.  On the x86 the syscall is
-	 *  just another trap and the return value from syscall is
-	 *  ignored.  On other machines the return value is put into
-	 *  the results register by caller of syscall.
-	 */
-	ureg->ax = ret;
-
-	if(up->procctl == Proc_tracesyscall){
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-
-	up->insyscall = 0;
-	up->psstate = 0;
-	INTRLOG(dprint("cleared insyscall\n");)
-	if(scallnr == NOTED)
-		noted(ureg, *(ulong*)(sp+BY2WD));
-
-	splhi();
-	if(scallnr!=RFORK && (up->procctl || up->nnote))
+	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->ax);
+	if(up->procctl || up->nnote)
 		notify(ureg);
 	/* if we delayed sched because we held a lock, sched now */
 	if(up->delaysched)
 		sched();
-	INTRLOG(dprint("before kexit\n");)
 	kexit(ureg);
 }
 
@@ -519,7 +434,7 @@
  *   Return user to state before notify()
  */
 void
-noted(Ureg* ureg, ulong arg0)
+noted(Ureg* ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
@@ -541,8 +456,8 @@
 	/* sanity clause */
 	oureg = (ulong)nureg;
 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
-		pprint("bad ureg in noted or call to noted when not notified\n");
 		qunlock(&up->debug);
+		pprint("bad ureg in noted or call to noted when not notified\n");
 		pexit("Suicide", 0);
 	}
 
@@ -561,8 +476,8 @@
 		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);
-		pprint("ss is %#lux, wanted %#ux\n", nureg->ss, UDSEL);
 		qunlock(&up->debug);
+		pprint("ss is %#lux, wanted %#ux\n", nureg->ss, UDSEL);
 		pexit("Suicide", 0);
 	}
 
@@ -582,19 +497,18 @@
 
 	case NSAVE:
 		sp = oureg-4*BY2WD-ERRMAX;
-		ureg->usp = sp;
-		if(!okaddr(ureg->pc, 1, 0) || !okaddr(ureg->usp, 4*BY2WD, 1)){
+		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);
+		ureg->usp = sp;
 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
 		break;
 
 	default:
-		pprint("unknown noted arg 0x%lux\n", arg0);
 		up->lastnote->flag = NDebug;
 		/* fall through */
 		
--- a/sys/src/9/zynq/fns.h
+++ b/sys/src/9/zynq/fns.h
@@ -45,7 +45,6 @@
 void setasid(ulong);
 void flushtlb(void);
 void touser(void *);
-void noted(Ureg *, ulong);
 void l1switch(L1 *, int);
 void intrenable(int, void (*)(Ureg *, void *), void *, int, char *);
 void intrinit(void);
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -214,82 +214,16 @@
 	}
 }
 
-#include "../port/systab.h"
-
 void
 syscall(Ureg *ureg)
 {
-	char *e;
-	uintptr sp;
-	long ret;
-	int i, s;
 	ulong scallnr;
-	vlong startns, stopns;
 	
 	if(!kenter(ureg))
 		panic("syscall: pc=%#.8lux", ureg->pc);
-	
-	m->syscall++;
-	up->insyscall = 1;
-	up->pc = ureg->pc;
-	
-	sp = ureg->sp;
-	up->scallnr = scallnr = ureg->r0;
-
-	spllo();
-	
-	ret = -1;
-	if(!waserror()){
-		if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
-			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
-			evenaddr(sp);
-		}
-		up->s = *((Sargs*) (sp + BY2WD));
-		
-		if(up->procctl == Proc_tracesyscall){
-			syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
-			s = splhi();
-			up->procctl = Proc_stopme;
-			procctl();
-			splx(s);
-			todget(nil, &startns);
-		}
-		if(scallnr >= nsyscall || systab[scallnr] == nil){
-			postnote(up, 1, "sys: bad sys call", NDebug);
-			error(Ebadarg);
-		}
-		up->psstate = sysctab[scallnr];
-		ret = systab[scallnr]((va_list)up->s.args);
-		poperror();
-	}else{
-		e = up->syserrstr;
-		up->syserrstr = up->errstr;
-		up->errstr = e;
-	}
-	if(up->nerrlab){
-		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
-		for(i = 0; i < NERR; i++)
-			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
-		panic("error stack");
-	}
-	
-	ureg->r0 = ret;
-	if(up->procctl == Proc_tracesyscall){
-		todget(nil, &stopns);
-		sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
-		s = splhi();
-		up->procctl = Proc_stopme;
-		procctl();
-		splx(s);
-	}
-	
-	up->insyscall = 0;
-	up->psstate = 0;
-	if(scallnr == NOTED)
-		noted(ureg, *((ulong *) up->s.args));
-
-	splhi();
-	if(scallnr != RFORK && (up->procctl || up->nnote))
+	scallnr = ureg->r0;
+	dosyscall(scallnr, (Sargs*)(ureg->sp + BY2WD), &ureg->r0);
+	if(up->procctl || up->nnote)
 		notify(ureg);
 	if(up->delaysched)
 		sched();
@@ -391,7 +325,7 @@
 }
 
 void
-noted(Ureg *ureg, ulong arg0)
+noted(Ureg *ureg, int arg0)
 {
 	Ureg *nureg;
 	ulong oureg, sp;
@@ -432,15 +366,14 @@
 	
 	case NSAVE:
 		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){
+		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);
+		ureg->sp = sp;
+		ureg->r0 = (uintptr) oureg;
 		((ulong *) sp)[1] = oureg;
 		((ulong *) sp)[0] = 0;
 		break;
--