~kris/9p

9hist

0c132ec3c5acfc131b2f9005c68e3262a0f4a040 — David du Colombier 35 years ago 5f83734
Plan 9 from Bell Labs 1991-07-17
M gnot/dat.h => gnot/dat.h +1 -0
@@ 219,6 219,7 @@ struct User
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);
	void	*ureg;
	ushort	svsr;

M gnot/lib.h => gnot/lib.h +3 -0
@@ 74,6 74,9 @@ extern	long	end;
#define	OCEXEC	32	/* or'ed in, close on exec */
#define	ORCLOSE	64	/* or'ed in, remove on close */

#define	NCONT	0	/* continue after note */
#define	NTERM	1	/* terminate after note */

typedef struct Qid	Qid;
typedef struct Dir	Dir;
typedef struct Waitmsg	Waitmsg;

M gnot/main.c => gnot/main.c +0 -1
@@ 132,7 132,6 @@ init0(void)
	}
	poperror();

	kickpager();
	touser();
}


M gnot/trap.c => gnot/trap.c +24 -6
@@ 8,7 8,7 @@
#include	"errno.h"

void	notify(Ureg*);
void	noted(Ureg*);
void	noted(Ureg*, ulong);
void	rfnote(Ureg*);

char *regname[]={


@@ 174,6 174,7 @@ notify(Ureg *ur)
		ur->pc = (ulong)u->notify;
		u->notified = 1;
		u->nnote--;
		memmove(&u->lastnote, &u->note[0], sizeof(Note));
		memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note));
	}
	unlock(&u->p->debug);


@@ 183,7 184,7 @@ notify(Ureg *ur)
 * Return user to state before notify()
 */
void
noted(Ureg *ur)
noted(Ureg *ur, ulong arg0)
{
	Ureg *nur;



@@ 201,9 202,26 @@ noted(Ureg *ur)
	}
	u->notified = 0;
	memmove(ur, u->ureg, sizeof(Ureg));
	unlock(&u->p->debug);
	splhi();
	rfnote(ur);
	ur->r0 = -1;	/* return error from the interrupted call */
	switch(arg0){
	case NCONT:
		splhi();
		unlock(&u->p->debug);
		rfnote(ur);
		break;
		/* never returns */

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		u->lastnote.flag = NDebug;
		/* fall through */
		
	case NTERM:
		if(u->lastnote.flag == NDebug)
			pprint("suicide: %s\n", u->lastnote.msg);
		unlock(&u->p->debug);
		pexit(u->lastnote.msg, u->lastnote.flag!=NDebug);
	}
}

#undef	CHDIR	/* BUG */


@@ 316,7 334,7 @@ syscall(Ureg *aur)
	u->p->insyscall = 0;

	if(r0 == NOTED)		/* ugly hack */
		noted(aur);	/* doesn't return */
		noted(aur, *(ulong*)(sp+BY2WD));	/* doesn't return */
	if(u->nnote){
		ur->r0 = ret;
		notify(ur);

M pc/dat.h => pc/dat.h +5 -1
@@ 4,6 4,7 @@ typedef struct Label	Label;
typedef struct Lock	Lock;
typedef struct MMU	MMU;
typedef struct Mach	Mach;
typedef struct Page	Page;
typedef struct PMMU	PMMU;
typedef struct Segdesc	Segdesc;
typedef struct Ureg	Ureg;


@@ 96,9 97,11 @@ struct Conf
/*
 *  MMU stuff in proc
 */
#define MAXMMU	4
struct PMMU
{
	MMU	*mmu;
	ulong	mmuent[MAXMMU];	/* a process' mmu entries */
	Page	*mmupg[MAXMMU];	/* mmu pages */
};

#include "../port/portdat.h"


@@ 157,6 160,7 @@ struct User
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);
	void	*ureg;
	ushort	svvo;

M pc/fns.h => pc/fns.h +5 -0
@@ 45,9 45,14 @@ void	kbdinit(void);
void	kbdintr(Ureg*);
void	lgdt(Segdesc*, int);
void	lidt(Segdesc*, int);
void	lcr3(ulong);
void	ltr(ulong);
void	mmuinit(void);
void	outb(int, int);
void	prhex(ulong);
void	procrestore(Proc*, uchar*);
void	procsave(uchar*, int);
void	procsetup(Proc*);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);

M pc/l.s => pc/l.s +23 -5
@@ 133,6 133,15 @@ setpte:
	MOVL	AX,CR0

	/*
	 *  use a jump to an absolute location to get the PC into
	 *  KZERO.
	 */
	LEAL	tokzero(SB),AX
	JMP*	AX

TEXT	tokzero(SB),$0

	/*
	 *  stack and mach
	 */
	MOVL	$mach0(SB),SP


@@ 206,7 215,7 @@ TEXT	tas(SB),$0
	RET

/*
 *  load the idt
 *  routines to load various system registers
 */
GLOBL	idtptr(SB),$6
TEXT	lidt(SB),$0


@@ 217,9 226,6 @@ TEXT	lidt(SB),$0
	MOVL	idtptr(SB),IDTR
	RET

/*
 *  load the gdt
 */
GLOBL	gdtptr(SB),$6
TEXT	lgdt(SB),$0
	MOVL	t+0(FP),AX


@@ 229,6 235,16 @@ TEXT	lgdt(SB),$0
	MOVL	gdtptr(SB),GDTR
	RET

TEXT	lcr3(SB),$0
	MOVL	t+0(FP),AX
	MOVL	AX,CR3
	RET

TEXT	ltr(SB),$0
	MOVL	t+0(FP),AX
	MOVW	AX,TASK
	RET

/*
 *  special traps
 */


@@ 403,13 419,15 @@ TEXT	setlabel(SB),$0
	RET

TEXT	touser(SB),$0
	MOVL	$(USERADDR+BY2PG-5*BY2WD),AX
	MOVL	$(USERADDR+BY2PG-6*BY2WD),AX
	MOVL	$(UTZERO+32),0(AX)	/* header is in text */
	MOVL	$(UESEL),4(AX)
	MOVL	$(IFLAG|2),8(AX)
	MOVL	$(USTKTOP-4*BY2WD),12(AX)
	MOVL	$(UDSEL),16(AX)
	MOVL	AX,SP
	MOVL	$(UDSEL),AX		/* set up data segment */
	MOVW	AX,DS
	IRETL

/*

M pc/main.c => pc/main.c +15 -14
@@ 20,7 20,9 @@ main(void)
	print("%d pages in bank0, %d pages in bank1\n", conf.npage0, conf.npage1);
	print("edata == %lux, end == %lux\n", &edata, &end);
	mmuinit();
print("mmu inited\n");
	procinit0();
print("proc inited\n");
	initseg();
	grpinit();
	chaninit();


@@ 31,6 33,7 @@ main(void)
	swapinit();
	pageinit();
	userinit();
print("user inited\n");

	schedinit();
}


@@ 94,9 97,12 @@ userinit(void)

	/*
	 * Kernel Stack
	 *
	 * N.B. The -4 for the stack pointer is important.  Gotolabel
	 *	uses the bottom 4 bytes of stack to store it's return pc.
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR + BY2PG - 24;
	p->sched.sp = USERADDR + BY2PG - 4;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));

	/*


@@ 126,18 132,6 @@ userinit(void)
	ready(p);
}

void
exit(void)
{
	int i;

	u = 0;
	splhi();
	print("exiting\n");
	for(;;)
		;
}

Conf	conf;

void


@@ 185,7 179,7 @@ confinit(void)
	conf.base1 = 1024/4;

	conf.npage = conf.npage0 + conf.npage1;
	conf.maxialloc = (640*1024-256*1024-BY2PG);
	conf.maxialloc = (conf.npage0*BY2PG-PGROUND((ulong)&end));

	mul = 1;
	conf.nproc = 20 + 50*mul;


@@ 269,3 263,10 @@ void
lights(int val)
{
}

int
mouseputc(IOQ *q, int c)
{
	return c;
}


M pc/mem.h => pc/mem.h +4 -1
@@ 59,7 59,8 @@
#define	UESEG	4	/* user executable */
#define	SYSGATE	5	/* system call gate */
#define	RDSEG	6	/* reboot data/stack */
#define	RESEG	7	/* reboot executable */	
#define	RESEG	7	/* reboot executable */
#define TSSSEG	8	/* task segment */

#define SELGDT	(0<<3)	/* selector is in gdt */
#define	SELLDT	(1<<3)	/* selector is in ldt */


@@ 73,12 74,14 @@
#define UDSEL	SELECTOR(UDSEG, SELGDT, 3)
#define RDSEL	SELECTOR(RDSEG, SELGDT, 0)
#define RESEL	SELECTOR(RESEG, SELGDT, 0)
#define TSSSEL	SELECTOR(TSSSEG, SELGDT, 0)

/*
 *  fields in segment descriptors
 */
#define SEGDATA	(0x10<<8)	/* data/stack segment */
#define SEGEXEC	(0x18<<8)	/* executable segment */
#define	SEGTSS	(0x9<<8)	/* TSS segment */
#define SEGCG	(0x0C<<8)	/* call gate */
#define	SEGIG	(0x0E<<8)	/* interrupt gate */
#define SEGTG	(0x0F<<8)	/* task gate */

M pc/mmu.c => pc/mmu.c +80 -19
@@ 16,11 16,11 @@ typedef struct Tss	Tss;
struct Tss
{
	ulong	backlink;	/* unused */
	ulong	esp0;		/* pl0 stack pointer */
	ulong	sp0;		/* pl0 stack pointer */
	ulong	ss0;		/* pl0 stack selector */
	ulong	esp1;		/* pl1 stack pointer */
	ulong	sp1;		/* pl1 stack pointer */
	ulong	ss1;		/* pl1 stack selector */
	ulong	esp2;		/* pl2 stack pointer */
	ulong	sp2;		/* pl2 stack pointer */
	ulong	ss2;		/* pl2 stack selector */
	ulong	cr3;		/* page table descriptor */
	ulong	eip;		/* instruction pointer */


@@ 42,15 42,18 @@ struct Tss
	ulong	ldt;		/* local descriptor table */
	ulong	iomap;		/* io map base */
};
Tss tss;

/*
 *  segment descriptor initializers
 */
#define	DATASEG(p) 	{ 0xFFFF, SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define	EXECSEG(p) 	{ 0xFFFF, SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define CALLGATE(s,o,p)	{ (o)&0xFFFF|((s)<<16), (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG }
#define	D16SEG(p) 	{ 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define	E16SEG(p) 	{ 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define	DATASEGM(p) 	{ 0xFFFF, SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define	EXECSEGM(p) 	{ 0xFFFF, SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define CALLGATE(s,o,p)	{ ((o)&0xFFFF)|((s)<<16), (o)&0xFFFF0000|SEGP|SEGPL(p)|SEGCG }
#define	D16SEGM(p) 	{ 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW }
#define	E16SEGM(p) 	{ 0xFFFF, (0x0<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR }
#define	TSSSEGM(b,p)	{ ((b)<<16)|sizeof(Tss),\
			  ((b)&0xFF000000)|(((b)<<16)&0xFF)|SEGTSS|SEGPL(p)|SEGP }

/*
 *  global descriptor table describing all segments


@@ 58,39 61,85 @@ struct Tss
Segdesc gdt[] =
{
[NULLSEG]	{ 0, 0},		/* null descriptor */
[KDSEG]		DATASEG(0),		/* kernel data/stack */
[KESEG]		EXECSEG(0),		/* kernel code */
[UDSEG]		DATASEG(3),		/* user data/stack */
[UESEG]		EXECSEG(3),		/* user code */
[KDSEG]		DATASEGM(0),		/* kernel data/stack */
[KESEG]		EXECSEGM(0),		/* kernel code */
[UDSEG]		DATASEGM(3),		/* user data/stack */
[UESEG]		EXECSEGM(3),		/* user code */
[SYSGATE]	CALLGATE(KESEL,0,3),	/* call gate for system calls */
[RDSEG]		D16SEG(0),		/* reboot data/stack */
[RESEG]		E16SEG(0),		/* reboot code */
[RDSEG]		D16SEGM(0),		/* reboot data/stack */
[RESEG]		E16SEGM(0),		/* reboot code */
[TSSSEG]	TSSSEGM(0,0),		/* tss segment */
};

extern ulong tpt[];
static ulong	*toppt;		/* top level page table */	
static ulong	*kpt;		/* kernel level page tables */
static ulong	*upt;		/* page table for struct User */

#define ROUNDUP(s,v)	(((s)+(v-1))&~(v-1))

void
mmuinit(void)
{
	int i, n, nkpt;
	ulong x;
	ulong y;

	/*
	 *  set up the global descriptor table
	 */
	gdt[SYSGATE].d0 = ((ulong)systrap)&0xFFFF|(KESEL<<16);
	gdt[SYSGATE].d1 = ((ulong)systrap)&0xFFFF0000|SEGP|SEGPL(3)|SEGCG;
	x = (ulong)systrap;
	gdt[SYSGATE].d0 = (x&0xFFFF)|(KESEL<<16);
	gdt[SYSGATE].d1 = (x&0xFFFF0000)|SEGP|SEGPL(3)|SEGCG;
	x = (long)&tss;
	gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss);
	gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP;
	lgdt(gdt, sizeof gdt);

	/*
	 *  set up system page tables
	 *  set up system page tables.
	 *  map all of physical memory to start at KZERO.
	 *  leave a map for a user area.
	 */

	/*  allocate and fill low level page tables for physical mem */
	nkpt = ROUNDUP(conf.npage0+conf.npage1, 4*1024*1024);
	nkpt = nkpt/(4*1024*1024);
	kpt = ialloc(nkpt*BY2PG, 1);
	n = ROUNDUP(conf.npage0+conf.npage1, 1*1024*1024);
	n = n/(4*1024);
	for(i = 0; i < n; i++){
		kpt[i] = (i<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE;
	}

	/*  allocate page table for u-> */
	upt = ialloc(BY2PG, 1);

	/*  allocate top level table and put pointers to lower tables in it */
	toppt = ialloc(BY2PG, 1);
	x = KZERO>>(2*PGSHIFT-2);
	y = ((ulong)kpt)&~KZERO;
	for(i = 0; i < nkpt; i++){
/*		toppt[i] = (y+i*BY2PG)|PTEVALID|PTEKERNEL|PTEWRITE;/**/
		toppt[x+i] = (y+i*BY2PG)|PTEVALID|PTEKERNEL|PTEWRITE;
	}
	x = USERADDR>>(2*PGSHIFT-2);
	y = ((ulong)upt)&~KZERO;
	toppt[x] = y|PTEVALID|PTEKERNEL|PTEWRITE;
	lcr3(((ulong)toppt)&~KZERO);

	/*
	 *  set up the task segment
	 */
	tss.sp0 = USERADDR;
	tss.ss0 = KDSEL;
	tss.cr3 = (ulong)toppt;
	ltr(TSSSEL);
}

void
mapstack(Proc *p)
{
	
}

void


@@ 104,7 153,7 @@ mmurelease(Proc *p)
}

void
putmmu(ulong x, ulong y, Page*z)
putmmu(ulong x, ulong y, Page *z)
{
}



@@ 118,3 167,15 @@ systrap(void)
{
	panic("system trap from user");
}

void
exit(void)
{
	int i;

	u = 0;
	print("exiting\n");
	for(i = 0; i < WD2PG; i++)
		toppt[i] = 0;
	lcr3(((ulong)toppt)&~KZERO);
}

M port/devcons.c => port/devcons.c +1 -0
@@ 727,6 727,7 @@ conswrite(Chan *c, void *va, long n, ulong offset)
		fd = strtoul(buf, 0, 0);
		swc = fdtochan(fd, -1);
		setswapchan(swc);
		kickpager();
		return n;

	default:

M port/lib.h => port/lib.h +3 -0
@@ 74,6 74,9 @@ extern	long	end;
#define	OCEXEC	32	/* or'ed in, close on exec */
#define	ORCLOSE	64	/* or'ed in, remove on close */

#define	NCONT	0	/* continue after note */
#define	NTERM	1	/* terminate after note */

typedef struct Qid	Qid;
typedef struct Dir	Dir;
typedef struct Waitmsg	Waitmsg;

M port/proc.c => port/proc.c +17 -10
@@ 67,7 67,7 @@ schedinit(void)		/* never returns */
			p->pid = 0;
			mmurelease(p);
			/* 
			 * Holding locks:
			 * Holding locks from pexit:
			 * 	procalloc, debug, palloc
			 */
			pg = p->upage;


@@ 473,7 473,7 @@ freebroken(void)
}

void
pexit(char *s, int freemem)
pexit(char *exitstr, int freemem)
{
	ulong mypid;
	Proc *p, *c, *k, *l;


@@ 481,9 481,10 @@ pexit(char *s, int freemem)
	Chan *ch;
	char msg[ERRLEN];
	ulong *up, *ucp, *wp;
	Segment **s, **es, *os;

	if(s) 	/* squirrel away; we'll lose our address space */
		strcpy(msg, s);
	if(exitstr) 			/* squirrel away before we lose our address space */
		strcpy(msg, exitstr);
	else
		msg[0] = 0;
	


@@ 496,9 497,12 @@ pexit(char *s, int freemem)

	if(freemem){
		flushvirt();
		for(i = 0; i < NSEG; i++)
			if(c->seg[i])
				putseg(c->seg[i]);
		es = &c->seg[NSEG];
		for(s = c->seg; s < es; s++)
			if(os = *s) {
				*s = 0;
				putseg(os);
			}
		closepgrp(c->pgrp);
		if(c->egrp)
			closeegrp(c->egrp);


@@ 552,9 556,12 @@ pexit(char *s, int freemem)
	if(!freemem){
		addbroken(c);
		flushvirt();
		for(i = 0; i < NSEG; i++)
			if(c->seg[i])
				putseg(c->seg[i]);
		es = &c->seg[NSEG];
		for(s = c->seg; s < es; s++)
			if(os = *s) {
				*s = 0;
				putseg(os);
			}
		closepgrp(c->pgrp);
		closeegrp(c->egrp);
		close(u->dot);

M power/dat.h => power/dat.h +1 -0
@@ 224,6 224,7 @@ struct User
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);
	void	*ureg;
	ulong	svstatus;

M power/main.c => power/main.c +0 -1
@@ 230,7 230,6 @@ init0(void)

	sp = (ulong*)(USTKTOP - argsize);

	kickpager();
	touser(sp);
}


M power/trap.c => power/trap.c +24 -12
@@ 12,7 12,7 @@
 */
void	(*vmevec[256])(int);

void	noted(Ureg**);
void	noted(Ureg**, ulong);
void	rfnote(Ureg**);

#define	LSYS	0x01


@@ 409,6 409,7 @@ notify(Ureg *ur)
		ur->pc = (ulong)u->notify;
		u->notified = 1;
		u->nnote--;
		memmove(&u->lastnote, &u->note[0], sizeof(Note));
		memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note));
	}
	unlock(&u->p->debug);


@@ 418,20 419,15 @@ notify(Ureg *ur)
 * Return user to state before notify()
 */
void
noted(Ureg **urp)
noted(Ureg **urp, ulong arg0)
{
	Ureg *nur;

	nur = u->ureg;
	if(waserror()){
		pprint("suicide: trap in noted\n");
		pexit("Suicide", 0);
	}
	validaddr(nur->pc, 1, 0);
	validaddr(nur->usp, BY2WD, 0);
	poperror();
	if(nur->status!=u->svstatus){
		pprint("bad noted ureg status %ux\n", nur->status);
		pprint("bad noted ureg status %lux\n", nur->status);
		pexit("Suicide", 0);
	}
	lock(&u->p->debug);


@@ 442,9 438,25 @@ noted(Ureg **urp)
	u->notified = 0;
	memmove(*urp, u->ureg, sizeof(Ureg));
	(*urp)->r1 = -1;	/* return error from the interrupted call */
	unlock(&u->p->debug);
	splhi();
	rfnote(urp);
	switch(arg0){
	case NCONT:
		splhi();
		unlock(&u->p->debug);
		rfnote(urp);
		break;
		/* never returns */

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		u->lastnote.flag = NDebug;
		/* fall through */
		
	case NTERM:
		if(u->lastnote.flag == NDebug)
			pprint("suicide: %s\n", u->lastnote.msg);
		unlock(&u->p->debug);
		pexit(u->lastnote.msg, u->lastnote.flag!=NDebug);
	}
}




@@ 558,7 570,7 @@ syscall(Ureg *aur)
	splhi();
	u->p->insyscall = 0;
	if(r1 == NOTED)	/* ugly hack */
		noted(&aur);	/* doesn't return */
		noted(&aur, *(ulong*)(sp+BY2WD));	/* doesn't return */
	if(u->nnote){
		ur->r1 = ret;
		notify(ur);

M ss/dat.h => ss/dat.h +2 -0
@@ 162,9 162,11 @@ struct User
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.
	 */
	ulong	svpsr;
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);
	void	*ureg;
};

M ss/faultsparc.c => ss/faultsparc.c +6 -3
@@ 10,6 10,7 @@ void
faultsparc(Ureg *ur)
{
	ulong addr, badvaddr;
	char buf[ERRLEN];
	int user, read;
	ulong tbr;



@@ 36,9 37,11 @@ faultsparc(Ureg *ur)

	if(fault(addr, read) < 0){
		if(user){
			pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
			pprint("psr=0x%lux pc=0x%lux sp=0x%lux\n", ur->psr, ur->pc, ur->sp);
			pexit("Suicide", 0);
			sprint(buf, "sys: fault %s pc=0x%lux addr=0x%lux",
				read? "read" : "write", ur->pc, badvaddr);
			postnote(u->p, 1, buf, NDebug);
			notify(ur);
			return;
		}
		u->p->state = MMUing;
		dumpregs(ur);

M ss/main.c => ss/main.c +0 -1
@@ 110,7 110,6 @@ init0(void)
	u->slash = (*devtab[0].attach)(0);
	u->dot = clone(u->slash, 0);

	kickpager(); /**/
	touser(USTKTOP-(1+MAXSYSARG)*BY2WD);
}


M ss/trap.c => ss/trap.c +33 -6
@@ 8,7 8,7 @@
#include	"errno.h"

void	notify(Ureg*);
void	noted(Ureg**);
void	noted(Ureg**, ulong);
void	rfnote(Ureg**);

extern	void traplink(void);


@@ 232,6 232,7 @@ notify(Ureg *ur)
	if(!u->notified){
		if(!u->notify)
			goto Die;
		u->svpsr = ur->psr;
		sp = ur->usp;
		sp -= sizeof(Ureg);
		u->ureg = (void*)sp;


@@ 247,6 248,7 @@ notify(Ureg *ur)
		ur->npc = (ulong)u->notify+4;
		u->notified = 1;
		u->nnote--;
		memmove(&u->lastnote, &u->note[0], sizeof(Note));
		memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note));
	}
	unlock(&u->p->debug);


@@ 256,8 258,17 @@ notify(Ureg *ur)
 * Return user to state before notify()
 */
void
noted(Ureg **urp)
noted(Ureg **urp, ulong arg0)
{
	Ureg *nur;

	nur = u->ureg;
	validaddr(nur->pc, 1, 0);
	validaddr(nur->usp, BY2WD, 0);
	if(nur->psr!=u->svpsr){
		pprint("bad noted ureg psr %lux\n", nur->psr);
		pexit("Suicide", 0);
	}
	lock(&u->p->debug);
	if(!u->notified){
		unlock(&u->p->debug);


@@ 266,9 277,25 @@ noted(Ureg **urp)
	u->notified = 0;
	memmove(*urp, u->ureg, sizeof(Ureg));
	(*urp)->r7 = -1;	/* return error from the interrupted call */
	unlock(&u->p->debug);
	splhi();
	rfnote(urp);
	switch(arg0){
	case NCONT:
		splhi();
		unlock(&u->p->debug);
		rfnote(urp);
		break;
		/* never returns */

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		u->lastnote.flag = NDebug;
		/* fall through */
		
	case NTERM:
		if(u->lastnote.flag == NDebug)
			pprint("suicide: %s\n", u->lastnote.msg);
		unlock(&u->p->debug);
		pexit(u->lastnote.msg, u->lastnote.flag!=NDebug);
	}
}

#undef	CHDIR	/* BUG */


@@ 376,7 403,7 @@ syscall(Ureg *aur)
	}
	u->p->insyscall = 0;
	if(r7 == NOTED)	/* ugly hack */
		noted(&aur);	/* doesn't return */
		noted(&aur, *(ulong*)(sp+1*BY2WD));	/* doesn't return */
	if(u->nnote){
		ur->r7 = ret;
		notify(ur);