shithub: riscv

Download patch

ref: c6c2e04d4a700fe3982a4a72e768c69d6ace08a6
parent: b429f72eaedff27b43c4ac951cea62f574e6fb23
author: cinap_lenrek <cinap_lenrek@localhost>
date: Tue Jul 12 11:46:22 EDT 2011

segdesc: add /dev/^(ldt gdt) support

--- a/sys/src/9/alphapc/fns.h
+++ b/sys/src/9/alphapc/fns.h
@@ -88,6 +88,7 @@
 #define	procrestore(p)
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 void	restfpregs(FPsave*);
 uvlong	rpcc(uvlong*);
 void	screeninit(void);
--- a/sys/src/9/alphapc/main.c
+++ b/sys/src/9/alphapc/main.c
@@ -272,6 +272,11 @@
 }
 
 void
+procfork(Proc *)
+{
+}
+
+void
 procsave(Proc *p)
 {
 	if(p->fpstate == FPactive){
--- a/sys/src/9/bitsy/fns.h
+++ b/sys/src/9/bitsy/fns.h
@@ -85,6 +85,7 @@
 #define	procrestore(p)
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 void	putdac(ulong);
 void	putttb(ulong);
 void	putpid(ulong);
--- a/sys/src/9/bitsy/main.c
+++ b/sys/src/9/bitsy/main.c
@@ -243,6 +243,11 @@
 	p->fpstate = FPinit;
 }
 
+void
+procfork(Proc*)
+{
+}
+
 /*
  *  Save the mach dependent part of the process state.
  */
--- a/sys/src/9/kw/arch.c
+++ b/sys/src/9/kw/arch.c
@@ -126,6 +126,11 @@
 	fpusysprocsetup(p);
 }
 
+void
+procfork(Proc *)
+{
+}
+
 /*
  *  Save the mach dependent part of the process state.
  */
--- a/sys/src/9/kw/fns.h
+++ b/sys/src/9/kw/fns.h
@@ -68,6 +68,7 @@
 void	procrestore(Proc *);
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 extern void _reset(void);
 extern void setr13(int, u32int*);
 extern void syscallfmt(int syscallno, ulong pc, va_list list);
--- a/sys/src/9/mtx/fns.h
+++ b/sys/src/9/mtx/fns.h
@@ -85,6 +85,7 @@
 #define procrestore(p)
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 void	putdec(ulong);
 void	puthid0(ulong);
 void	puthid1(ulong);
--- a/sys/src/9/mtx/main.c
+++ b/sys/src/9/mtx/main.c
@@ -259,6 +259,11 @@
 	p->fpstate = FPinit;
 }
 
+void
+procfork(Proc *)
+{
+}
+
 /*
  *  Save the mach dependent part of the process state.
  */
--- a/sys/src/9/omap/arch.c
+++ b/sys/src/9/omap/arch.c
@@ -126,6 +126,11 @@
 	fpusysprocsetup(p);
 }
 
+void
+procfork(Proc*)
+{
+}
+
 /*
  *  Save the mach dependent part of the process state.
  */
--- a/sys/src/9/omap/fns.h
+++ b/sys/src/9/omap/fns.h
@@ -70,6 +70,7 @@
 extern void procrestore(Proc *);
 extern void procsave(Proc*);
 extern void procsetup(Proc*);
+extern void procfork(Proc*);
 extern void _reset(void);
 extern void screenclockson(void);
 extern void screeninit(void);
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -108,6 +108,12 @@
 	int	nuart;		/* number of uart devices */
 };
 
+struct Segdesc
+{
+	ulong	d0;
+	ulong	d1;
+};
+
 /*
  *  MMU stuff in proc
  */
@@ -120,6 +126,10 @@
 	Page*	kmaptable;		/* page table used by kmap */
 	uint	lastkmap;		/* last entry used by kmap */
 	int	nkmap;			/* number of current kmaps */
+
+	Segdesc	gdt[NPROCSEG];	/* per process descriptors */
+	Segdesc	*ldt;	/* local descriptor table */
+	int	nldt;	/* number of ldt descriptors allocated */
 };
 
 /*
@@ -162,12 +172,6 @@
 	ulong	ldt;			/* selector for task's LDT */
 	ulong	iomap;			/* I/O map base address + T-bit */
 } Tss;
-
-struct Segdesc
-{
-	ulong	d0;
-	ulong	d1;
-};
 
 struct Mach
 {
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -87,6 +87,7 @@
 void	kbdinit(void);
 #define	kmapinval()
 void	lgdt(ushort[3]);
+void	lldt(ulong);
 void	lidt(ushort[3]);
 void	links(void);
 void	ltr(ulong);
@@ -147,6 +148,7 @@
 void	procrestore(Proc*);
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 void	putcr0(ulong);
 void	putcr3(ulong);
 void	putcr4(ulong);
@@ -173,7 +175,6 @@
 ulong	upaalloc(int, int);
 void	upafree(ulong, int);
 void	upareserve(ulong, int);
-#define	userureg(ur) (((ur)->cs & 0xFFFF) == UESEL)
 void	vectortable(void);
 void*	vmap(ulong, int);
 int	vmapsync(ulong);
@@ -182,6 +183,7 @@
 void	wrmsr(int, vlong);
 int	xchgw(ushort*, int);
 
+#define	userureg(ur)	(((ur)->cs & 3) == 3)
 #define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
 #define	KADDR(a)	kaddr(a)
 #define PADDR(a)	paddr((void*)(a))
--- a/sys/src/9/pc/io.h
+++ b/sys/src/9/pc/io.h
@@ -10,6 +10,8 @@
 	VectorCNA	= 7,		/* coprocessor not available */
 	Vector2F	= 8,		/* double fault */
 	VectorCSO	= 9,		/* coprocessor segment overrun */
+	VectorSNP	= 11,		/* segment not present */
+	VectorGPF	= 13,		/* general protection fault */
 	VectorPF	= 14,		/* page fault */
 	Vector15	= 15,		/* reserved */
 	VectorCERR	= 16,		/* coprocessor error */
--- a/sys/src/9/pc/l.s
+++ b/sys/src/9/pc/l.s
@@ -243,6 +243,17 @@
 	HLT
 	JMP	_idle
 
+
+TEXT load_fs(SB), $0
+	MOVW fs+0(FP), AX
+	MOVW AX, FS
+	RET
+
+TEXT load_gs(SB), $0
+	MOVW gs+0(FP), AX
+	MOVW AX, GS
+	RET
+
 /*
  * Save registers.
  */
@@ -599,6 +610,11 @@
 TEXT lgdt(SB), $0				/* GDTR - global descriptor table */
 	MOVL	gdtptr+0(FP), AX
 	MOVL	(AX), GDTR
+	RET
+
+TEXT lldt(SB), $0				/* LDTR - local descriptor table */
+	MOVL	sel+0(FP), AX
+	BYTE $0x0F; BYTE $0x00; BYTE $0xD0	/* LLDT AX */
 	RET
 
 TEXT lidt(SB), $0				/* IDTR - interrupt descriptor table */
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -225,8 +225,7 @@
 	kstrdup(&p->text, "*init*");
 	kstrdup(&p->user, eve);
 
-	p->fpstate = FPinit;
-	fpoff();
+	procsetup(p);
 
 	/*
 	 * Kernel Stack
@@ -585,6 +584,24 @@
 {
 	p->fpstate = FPinit;
 	fpoff();
+
+	memset(p->gdt, 0, sizeof(p->gdt));
+	p->ldt = nil;
+	p->nldt = 0;
+}
+
+void
+procfork(Proc *p)
+{
+	/* inherit user descriptors */
+	memmove(p->gdt, up->gdt, sizeof(p->gdt));
+
+	/* copy local descriptor table */
+	if(up->ldt != nil && up->nldt > 0){
+		p->ldt = malloc(sizeof(Segdesc) * up->nldt);
+		memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt);
+		p->nldt = up->nldt;
+	}
 }
 
 void
--- a/sys/src/9/pc/mem.h
+++ b/sys/src/9/pc/mem.h
@@ -92,8 +92,10 @@
 #define	APMCSEG16	7	/* APM 16-bit code segment */
 #define	APMDSEG		8	/* APM data segment */
 #define	KESEG16		9	/* kernel executable 16-bit */
-#define	NGDT		10	/* number of GDT entries required */
-/* #define	APM40SEG	8	/* APM segment 0x40 */
+#define	LDTSEG		10	/* local descriptor table */
+#define	PROCSEG0	11	/* per process descriptor0 */
+#define	NPROCSEG	3	/* number of per process descriptors */
+#define	NGDT		14	/* number of GDT entries required */
 
 #define	SELGDT	(0<<2)	/* selector is in gdt */
 #define	SELLDT	(1<<2)	/* selector is in ldt */
@@ -109,7 +111,7 @@
 #define	APMCSEL 	SELECTOR(APMCSEG, SELGDT, 0)
 #define	APMCSEL16	SELECTOR(APMCSEG16, SELGDT, 0)
 #define	APMDSEL		SELECTOR(APMDSEG, SELGDT, 0)
-/* #define	APM40SEL	SELECTOR(APM40SEG, SELGDT, 0) */
+#define	LDTSEL	SELECTOR(LDTSEG, SELGDT, 0)
 
 /*
  *  fields in segment descriptors
@@ -120,6 +122,7 @@
 #define	SEGCG	(0x0C<<8)	/* call gate */
 #define	SEGIG	(0x0E<<8)	/* interrupt gate */
 #define	SEGTG	(0x0F<<8)	/* trap gate */
+#define	SEGLDT	(0x02<<8)	/* local descriptor table */
 #define	SEGTYPE	(0x1F<<8)
 
 #define	SEGP	(1<<15)		/* segment present */
--- a/sys/src/9/pc/mmu.c
+++ b/sys/src/9/pc/mmu.c
@@ -294,6 +294,8 @@
 mmuswitch(Proc* proc)
 {
 	ulong *pdb;
+	ulong x;
+	int n;
 
 	if(proc->newtlb){
 		mmuptefree(proc);
@@ -307,6 +309,14 @@
 		taskswitch(proc->mmupdb->pa, (ulong)(proc->kstack+KSTACK));
 	}else
 		taskswitch(PADDR(m->pdb), (ulong)(proc->kstack+KSTACK));
+
+	memmove(&m->gdt[PROCSEG0], proc->gdt, sizeof(proc->gdt));
+	if((x = (ulong)proc->ldt) && (n = proc->nldt) > 0){
+		m->gdt[LDTSEG].d0 = (x<<16)|((n * sizeof(Segdesc)) - 1);
+		m->gdt[LDTSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGLDT|SEGPL(0)|SEGP;
+		lldt(LDTSEL);
+	} else
+		lldt(NULLSEL);
 }
 
 /*
@@ -366,6 +376,11 @@
 	if(proc->mmufree && palloc.r.p)
 		wakeup(&palloc.r);
 	proc->mmufree = 0;
+	if(proc->ldt){
+		free(proc->ldt);
+		proc->ldt = nil;
+		proc->nldt = 0;
+	}
 }
 
 /*
--- a/sys/src/9/pc/pccpuf
+++ b/sys/src/9/pc/pccpuf
@@ -35,6 +35,7 @@
 	usb
 
 link
+	segdesc
 	realmode
 	devpccard
 	devi82365
--- a/sys/src/9/pc/pcf
+++ b/sys/src/9/pc/pcf
@@ -37,6 +37,7 @@
 	usb
 
 link
+	segdesc
 	realmode
 	devpccard
 	devi82365
--- /dev/null
+++ b/sys/src/9/pc/segdesc.c
@@ -1,0 +1,261 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/error.h"
+
+/*
+ * flags:
+ * P = present
+ * A = accessed (for code/data)
+ * E = expand down (for data)
+ * W = writable (for data)
+ * R = readable (for code)
+ * C = conforming (for code)
+ * G = limit granularity in pages (for code/data)
+ * D = 32 bit operand size (for code)
+ * B = 32 bit stack pointer (for data)
+ * Y = busy (for tss and tss16)
+ * U = available for use by system software
+ */
+
+static struct {
+	char	*name;
+	char	*flags;
+} descrtypes[] = {
+	"data",		"--------AWE01--P----U.BG--------",
+	"code",		"--------ARC11--P----U.DG--------",
+	"tss16",	"--------1Y000--P----U..G--------",
+	"ldt",		"--------01000--P----U..G--------",
+	"callg16",	"--------00100--P----U..G--------",
+	"taskg",	"--------10100--P----U..G--------",
+	"intrg16",	"--------01100--P----U..G--------",
+	"trapg16",	"--------11100--P----U..G--------",
+	"tss",		"--------1Y010--P----U..G--------",
+	"callg",	"--------00110--P----U..G--------",
+	"intrg",	"--------01110--P----U..G--------",
+	"trapg",	"--------11110--P----U..G--------",
+};
+
+/*
+ * format:
+ * idx[4] type[8] flags[8] dpl[1] base[8] limit[5]\n
+ */
+
+enum
+{
+	RECLEN	= 4+1 + 8+1 + 8+1 + 1+1 + 8+1 + 5+1,
+};
+
+static long
+descwrite(Proc *proc, int local, void *v, long n, vlong)
+{
+	int i, j, t;
+	char buf[RECLEN+1];
+	char c, *p, *s, *e, *f[6];
+	Segdesc d;
+
+	int dpl;
+	ulong base;
+	ulong limit;
+
+	s = (char*)v;
+	e = s + n;
+
+	if(waserror()){
+		if(proc == up)
+			flushmmu();
+		nexterror();
+	}
+
+	while(s < e){
+		for(p = s; p < e && *p != '\n'; p++);
+			;
+		if((p - s) > RECLEN)
+			error(Ebadarg);
+		memmove(buf, s, p - s);
+		buf[p-s] = 0;
+		s = p+1;
+
+		if(getfields(buf, f, nelem(f), 1, " ") != nelem(f))
+			error(Ebadarg);
+
+		i = strtoul(f[0], nil, 16);
+
+		for(t=0; t<nelem(descrtypes); t++)
+			if(strcmp(descrtypes[t].name, f[1]) == 0)
+				break;
+		if(t == nelem(descrtypes))
+			error(Ebadarg);
+
+		dpl = atoi(f[3]);
+		base = strtoul(f[4], nil, 16);
+		limit = strtoul(f[5], nil, 16);
+
+		d.d0 = ((base & 0xFFFF)<<16) | (limit & 0xFFFF);
+		d.d1 = (base & 0xFF000000) | (limit & 0xF0000) | ((dpl & 3)<<13) | ((base & 0xFF0000)>>16);
+
+		for(j=0; c = descrtypes[t].flags[j]; j++){
+			switch(c){
+			default:
+				if(strchr(f[2], c) == nil){
+			case '0':
+			case '.':
+					d.d1 &= ~(1<<j);
+					break;					
+				} else {
+			case '1':
+					d.d1 |= (1<<j);
+					break;
+				}
+			case '-':
+				continue;
+			}
+		}
+
+		/* dont allow system segments */
+		if((d.d1 & SEGP) && ((dpl != 3) || !(d.d1 & (1<<12))))
+			error(Eperm);
+		
+		if(local){
+			Segdesc *new, *old;
+			int c;
+
+			if(i < 0 || i >= 8192)
+				error(Ebadarg);
+			if(i >= (c = ((old = proc->ldt) ? proc->nldt : 0))){
+				if((new = malloc(sizeof(Segdesc) * (i+1))) == nil)
+					error(Enomem);
+				if(c > 0)
+					memmove(new, old, sizeof(Segdesc) * c);
+				memset(new + c, 0, sizeof(Segdesc) * ((i+1) - c));
+				proc->ldt = new;
+				proc->nldt = i+1;
+				free(old);
+			}
+			proc->ldt[i] = d;
+		} else {
+			if(i < PROCSEG0 || i >= PROCSEG0 + NPROCSEG)
+				error(Ebadarg);
+			proc->gdt[i - PROCSEG0] = d;
+		}
+	}
+	poperror();
+
+	if(proc == up)
+		flushmmu();
+
+	return n;
+}
+
+static long
+descread(Proc *proc, int local, void *v, long n, vlong o)
+{
+	int i, j, k, t;
+	char *s;
+
+	int dpl;
+	ulong base;
+	ulong limit;
+
+	s = v;
+	for(i = 0;;i++){
+		Segdesc d;
+
+		if(local){
+			if(proc->ldt == nil || i >= proc->nldt)
+				break;
+			d = proc->ldt[i];
+		} else {
+			if(i < PROCSEG0)
+				i = PROCSEG0;
+			if(i >= PROCSEG0 + NPROCSEG)
+				break;
+			d = proc->gdt[i - PROCSEG0];
+		}
+
+		if(o >= RECLEN){
+			o -= RECLEN;
+			continue;
+		}
+
+		if(s + RECLEN+1 >= (char*)v  + n)
+			break;
+
+		for(t=0; t<nelem(descrtypes); t++){
+			for(j=0; descrtypes[t].flags[j]; j++){
+				if(descrtypes[t].flags[j]=='0' && (d.d1 & (1<<j)) != 0)
+					break;
+				if(descrtypes[t].flags[j]=='1' && (d.d1 & (1<<j)) == 0)
+					break;
+			}
+			if(descrtypes[t].flags[j] == 0)
+				break;
+		}
+		if(t == nelem(descrtypes))
+			t = 0;
+
+		s += sprint(s, "%.4lux ", (ulong)i);
+		s += sprint(s, "%-8s ", descrtypes[t].name);
+
+		k = 0;
+		for(j=0; descrtypes[t].flags[j]; j++){
+			switch(descrtypes[t].flags[j]){
+			case '-':
+			case '.':
+			case '0':
+			case '1':
+				continue;
+			}
+			if(d.d1 & (1 << j))
+				s[k++] = descrtypes[t].flags[j];
+		}
+		if(k == 0)
+			s[k++] = '-';
+		while(k < 9)
+			s[k++] = ' ';
+		s += k;
+
+		dpl = (d.d1 & 0x6000)>>13;
+		base = ((d.d0 & 0xFFFF0000)>>16) | ((d.d1 & 0xFF)<<16) | (d.d1 & 0xFF000000);
+		limit = (d.d1 & 0xF0000) | (d.d0 & 0xFFFF);
+
+		s += sprint(s, "%.1d ", dpl);
+		s += sprint(s, "%.8lux ", base);
+		s += sprint(s, "%.5lux\n", limit);
+	}
+
+	return s-(char*)v;
+}
+
+static long
+gdtread(Chan*, void *v, long n, vlong o)
+{
+	return descread(up, 0, v, n, o);
+}
+
+static long
+gdtwrite(Chan*, void *v, long n, vlong o)
+{
+	return descwrite(up, 0, v, n, o);
+}
+
+static long
+ldtread(Chan*, void *v, long n, vlong o)
+{
+	return descread(up, 1, v, n, o);
+}
+
+static long
+ldtwrite(Chan*, void *v, long n, vlong o)
+{
+	return descwrite(up, 1, v, n, o);
+}
+
+void
+segdesclink(void)
+{
+	addarchfile("gdt", 0666, gdtread, gdtwrite);
+	addarchfile("ldt", 0666, ldtread, ldtwrite);
+}
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -326,7 +326,7 @@
 	}
 
 	m->perf.intrts = perfticks();
-	user = (ureg->cs & 0xFFFF) == UESEL;
+	user = userureg(ureg);
 	if(user){
 		up->dbgreg = ureg;
 		cycles(&up->kentry);
@@ -424,6 +424,48 @@
 			while(m->machno != 0)
 				;
 		}
+
+		if(vno == VectorGPF || vno == VectorSNP){
+			ulong *sp;
+			uchar *pc;
+
+			/* l.s */
+			extern void load_fs(ulong);
+			extern void load_gs(ulong);
+
+			/*
+			 * CS, SS, DS and ES are initialized by strayintr
+			 * in l.s. initialize the others too so we dont trap
+			 * again when restoring the old context.
+			 */
+			load_fs(NULLSEL);
+			load_gs(NULLSEL);
+
+			pc = (uchar*)ureg->pc;
+			sp = (ulong*)&ureg->sp;
+
+			/*
+			 * we test for the instructions used by forkret()
+			 * to load the segments. this needs to be changed
+			 * if forkret changes!
+			 */
+
+			/* POP */
+			if((pc[0] == 0x0f && (pc[1] == 0xa9 /*GS*/ || 
+				pc[1] == 0xa1 /*FS*/)) || (pc[0] == 0x07) /*ES*/ ||	
+				(pc[0] == 0x1f) /*DS*/){
+				sp[0] = NULLSEL;
+				return;
+			}
+
+			/* IRET */
+			if(pc[0] == 0xcf){
+				sp[1] = UESEL;	/*CS*/
+				sp[4] = UDSEL;	/*SS*/
+				return;
+			}
+		}
+
 		dumpregs(ureg);
 		if(!user){
 			ureg->sp = (ulong)&ureg->sp;
@@ -461,7 +503,10 @@
 		iprint("cpu%d: registers for kernel\n", m->machno);
 	iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
-	iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
+	if(userureg(ureg))
+		iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
+	else
+		iprint(" SP=%luX\n", (ulong)&ureg->sp);
 	iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
 	iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
@@ -619,7 +664,7 @@
 	addr = getcr2();
 	read = !(ureg->ecode & 2);
 
-	user = (ureg->cs & 0xFFFF) == UESEL;
+	user = userureg(ureg);
 	if(!user){
 		if(vmapsync(addr))
 			return;
@@ -666,7 +711,7 @@
 	ulong scallnr;
 	vlong startns, stopns;
 
-	if((ureg->cs & 0xFFFF) != UESEL)
+	if(!userureg(ureg))
 		panic("syscall: cs 0x%4.4luX", ureg->cs);
 
 	cycles(&up->kentry);
@@ -850,6 +895,8 @@
 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
 	ureg->usp = sp;
 	ureg->pc = (ulong)up->notify;
+	ureg->cs = UESEL;
+	ureg->ss = ureg->ds = ureg->es = UDSEL;
 	up->notified = 1;
 	up->nnote--;
 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
@@ -889,23 +936,10 @@
 		pexit("Suicide", 0);
 	}
 
-	/*
-	 * Check the segment selectors are all valid, otherwise
-	 * a fault will be taken on attempting to return to the
-	 * user process.
-	 * Take care with the comparisons as different processor
-	 * generations push segment descriptors in different ways.
-	 */
-	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){
-		qunlock(&up->debug);
-		pprint("bad segment selector in noted\n");
-		pexit("Suicide", 0);
-	}
-
 	/* don't let user change system flags */
 	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
+	nureg->cs |= 3;
+	nureg->ss |= 3;
 
 	memmove(ureg, nureg, sizeof(Ureg));
 
@@ -968,6 +1002,9 @@
 	ureg = up->dbgreg;
 	ureg->usp = (ulong)sp;
 	ureg->pc = entry;
+	ureg->cs = UESEL;
+	ureg->ss = ureg->ds = ureg->es = UDSEL;
+	ureg->fs = ureg->gs = NULLSEL;
 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
 }
 
@@ -989,23 +1026,13 @@
 void
 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
 {
-	ulong cs, ds, es, flags, fs, gs, ss;
+	ulong flags;
 
-	ss = ureg->ss;
 	flags = ureg->flags;
-	cs = ureg->cs;
-	ds = ureg->ds;
-	es = ureg->es;
-	fs = ureg->fs;
-	gs = ureg->gs;
 	memmove(pureg, uva, n);
-	ureg->gs = gs;
-	ureg->fs = fs;
-	ureg->es = es;
-	ureg->ds = ds;
-	ureg->cs = cs;
-	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
-	ureg->ss = ss;
+	ureg->flags = (ureg->flags & 0xCD5) | (flags & ~0xCD5);
+	ureg->cs |= 3;
+	ureg->ss |= 3;
 }
 
 static void
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -187,6 +187,9 @@
 
 	kstrdup(&p->text, up->text);
 	kstrdup(&p->user, up->user);
+
+	procfork(p);
+
 	/*
 	 *  since the bss/data segments are now shareable,
 	 *  any mmu info about this process is now stale
@@ -472,11 +475,6 @@
 	poperror();
 	cclose(tc);
 
-	/*
-	 *  At this point, the mmu contains info about the old address
-	 *  space and needs to be flushed
-	 */
-	flushmmu();
 	qlock(&up->debug);
 	up->nnote = 0;
 	up->notify = 0;
@@ -484,9 +482,15 @@
 	up->privatemem = 0;
 	procsetup(up);
 	qunlock(&up->debug);
+
+	/*
+	 *  At this point, the mmu contains info about the old address
+	 *  space and needs to be flushed
+	 */
+	flushmmu();
+
 	if(up->hang)
 		up->procctl = Proc_stopme;
-
 	return execregs(entry, ssize, nargs);
 }
 
--- a/sys/src/9/ppc/fns.h
+++ b/sys/src/9/ppc/fns.h
@@ -77,6 +77,7 @@
 void	pcicfgw8(Pcidev*, int, int);
 void	procsave(Proc*);
 void	procsetup(Proc*);
+void	procfork(Proc*);
 void	putdcmp(ulong);
 void	putdec(ulong);
 void	puthash1(ulong);
--- a/sys/src/9/ppc/main.c
+++ b/sys/src/9/ppc/main.c
@@ -287,6 +287,11 @@
 }
 
 void
+procfork(Proc *)
+{
+}
+
+void
 procrestore(Proc *p)
 {
 	uvlong t;