shithub: riscv

Download patch

ref: 24057fd4f494a00573d34adeaa7042721c1a06a0
parent: 04ce485f1b4453335db70b4a1b5d2c96458db3c1
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 4 16:08:22 EDT 2017

kernel: introduce per process FPU struct (PFPU) for more flexible machine specific fpu handling

introducing the PFPU structue which allows the machine specific
code some flexibility on how to handle the FPU process state.

for example, in the pc and pc64 kernel, the FPsave structure is
arround 512 bytes. with avx512, it could grow up to 2K. instead
of embedding that into the Proc strucutre, it is more effective
to allocate it on first use of the fpu, as most processes do not
use simd or floating point in the first place. also, the FPsave
structure has special 16 byte alignment constraint, which further
favours dynamic allocation.

this gets rid of the memmoves in pc/pc64 kernels for the aligment.

there is also devproc, which is now checking if the fpsave area
is actually valid before reading it, avoiding debuggers to see
garbage data.

the Notsave structure is gone now, as it was not used on any
machine.

--- a/sys/src/9/bcm/dat.h
+++ b/sys/src/9/bcm/dat.h
@@ -15,6 +15,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
@@ -21,7 +22,6 @@
 typedef struct Memcache	Memcache;
 typedef struct MMMU	MMMU;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct PhysUart	PhysUart;
 typedef struct PMMU	PMMU;
@@ -56,14 +56,14 @@
 	uintptr	pc;
 };
 
+/*
+ * emulated or vfp3 floating point
+ */
 enum {
 	Maxfpregs	= 32,	/* could be 16 or 32, see Mach.fpnregs */
 	Nfpctlregs	= 16,
 };
 
-/*
- * emulated or vfp3 floating point
- */
 struct FPsave
 {
 	ulong	status;
@@ -78,9 +78,12 @@
 	uintptr	pc;		/* of failed fp instr. */
 };
 
-/*
- * FPsave.fpstate
- */
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
 enum
 {
 	FPinit,
@@ -117,13 +120,6 @@
 	ulong	hz;		/* processor cycle freq */
 	ulong	mhz;
 	int	monitor;	/* flag */
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave {
-	int	emptiness;
 };
 
 /*
--- a/sys/src/9/bcm/fpiarm.c
+++ b/sys/src/9/bcm/fpiarm.c
@@ -650,7 +650,7 @@
 
 	if(up == nil)
 		panic("fpiarm not in a process");
-	ufp = &up->fpsave;
+	ufp = up->fpsave;
 	/*
 	 * because all the emulated fp state is in the proc structure,
 	 * it need not be saved/restored
--- a/sys/src/9/bcm/vfp3.c
+++ b/sys/src/9/bcm/vfp3.c
@@ -222,7 +222,7 @@
 fpunotify(Ureg*)
 {
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
@@ -259,11 +259,11 @@
 	int n;
 
 	fpon();
-	fpwr(Fpscr, p->fpsave.control);
+	fpwr(Fpscr, p->fpsave->control);
 	m->fpscr = fprd(Fpscr) & ~Allcc;
 	assert(m->fpnregs);
 	for (n = 0; n < m->fpnregs; n++)
-		fprestreg(n, *(uvlong *)p->fpsave.regs[n]);
+		fprestreg(n, *(uvlong *)p->fpsave->regs[n]);
 }
 
 /*
@@ -288,7 +288,7 @@
 			 * until the process runs again and generates an
 			 * emulation fault to activate the FPU.
 			 */
-			fpsave(&p->fpsave);
+			fpsave(p->fpsave);
 		}
 		p->fpstate = FPinactive;
 	}
@@ -317,11 +317,11 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 		/* no break */
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	splx(s);
@@ -345,7 +345,7 @@
 	ulong status;
 	char *msg, note[ERRMAX];
 
-	status = up->fpsave.status;
+	status = up->fpsave->status;
 
 	/*
 	 * Some attention should probably be paid here to the
@@ -364,7 +364,7 @@
 	else
 		msg = "spurious";
 	snprint(note, sizeof note, "sys: fp: %s fppc=%#p status=%#lux",
-		msg, up->fpsave.pc, status);
+		msg, up->fpsave->pc, status);
 	postnote(up, 1, note, NDebug);
 }
 
@@ -388,7 +388,7 @@
 		 * More attention should probably be paid here to the
 		 * exception masks and error summary.
 		 */
-		if(up->fpsave.status & (FPAINEX|FPAUNFL|FPAOVFL|FPAZDIV|FPAINVAL)){
+		if(up->fpsave->status & (FPAINEX|FPAUNFL|FPAOVFL|FPAZDIV|FPAINVAL)){
 			mathnote();
 			break;
 		}
--- a/sys/src/9/kw/dat.h
+++ b/sys/src/9/kw/dat.h
@@ -1,6 +1,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
@@ -7,7 +8,6 @@
 typedef struct Memcache	Memcache;
 typedef struct MMMU	MMMU;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct Pcidev	Pcidev;
 typedef struct PhysUart	PhysUart;
@@ -45,13 +45,13 @@
 	uintptr	pc;
 };
 
+/*
+ * emulated floating point
+ */
 enum{
 	Nfpctlregs = 16,
 };
 
-/*
- * emulated floating point
- */
 struct FPsave
 {
 	ulong	status;
@@ -61,9 +61,12 @@
 	int	fpstate;
 };
 
-/*
- * FPsave.status
- */
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
 enum
 {
 	FPinit,
@@ -96,13 +99,6 @@
 	int	nswppo;		/* max # of pageouts per segment pass */
 //	ulong	hz;		/* processor cycle freq */
 //	ulong	mhz;
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave {
-	int	emptiness;
 };
 
 /*
--- a/sys/src/9/kw/fpiarm.c
+++ b/sys/src/9/kw/fpiarm.c
@@ -726,7 +726,7 @@
 
 	if(up == nil)
 		panic("fpiarm not in a process");
-	ufp = &up->fpsave;
+	ufp = up->fpsave;
 	/*
 	 * because all the emulated fp state is in the proc structure,
 	 * it need not be saved/restored
--- a/sys/src/9/mtx/dat.h
+++ b/sys/src/9/mtx/dat.h
@@ -1,11 +1,11 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct PCArch	PCArch;
 typedef struct Pcidev	Pcidev;
@@ -46,16 +46,6 @@
 };
 
 /*
- * Proc.fpstate
- */
-enum
-{
-	FPinit,
-	FPactive,
-	FPinactive,
-};
-
-/*
  * This structure must agree with fpsave and fprestore asm routines
  */
 struct	FPsave
@@ -70,6 +60,19 @@
 	};
 };
 
+struct	PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
+enum
+{
+	FPinit,
+	FPactive,
+	FPinactive,
+};
+
 struct Confmem
 {
 	ulong	base;
@@ -101,14 +104,6 @@
 struct PMMU
 {
 	int	mmupid;
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave
-{
-	ulong	UNUSED;
 };
 
 #include "../port/portdat.h"
--- a/sys/src/9/mtx/main.c
+++ b/sys/src/9/mtx/main.c
@@ -241,7 +241,7 @@
 {
 	if(p->fpstate == FPactive){
 		if(p->state != Moribund)
-			fpsave(&up->fpsave);
+			fpsave(up->fpsave);
 		p->fpstate = FPinactive;
 	}
 }
--- a/sys/src/9/mtx/trap.c
+++ b/sys/src/9/mtx/trap.c
@@ -246,7 +246,7 @@
 			up->fpstate = FPactive;
 			break;
 		case FPinactive:
-			fprestore(&up->fpsave);
+			fprestore(up->fpsave);
 			up->fpstate = FPactive;
 			break;
 		default:
--- a/sys/src/9/omap/dat.h
+++ b/sys/src/9/omap/dat.h
@@ -27,6 +27,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
@@ -34,7 +35,6 @@
 typedef struct MMMU	MMMU;
 typedef struct Mach	Mach;
 typedef u32int Mreg;				/* Msr - bloody UART */
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct PhysUart	PhysUart;
 typedef struct PMMU	PMMU;
@@ -69,13 +69,13 @@
 	uintptr	pc;
 };
 
+/*
+ * emulated floating point
+ */
 enum{
 	Nfpctlregs = 16,
 };
 
-/*
- * emulated floating point
- */
 struct FPsave
 {
 	ulong	status;
@@ -85,9 +85,12 @@
 	int	fpstate;
 };
 
-/*
- * FPsave.status
- */
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
 enum
 {
 	FPinit,
@@ -120,13 +123,6 @@
 	ulong	hz;		/* processor cycle freq */
 	ulong	mhz;
 	int	monitor;	/* flag */
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave {
-	int	emptiness;
 };
 
 /*
--- a/sys/src/9/omap/fpiarm.c
+++ b/sys/src/9/omap/fpiarm.c
@@ -726,7 +726,7 @@
 
 	if(up == nil)
 		panic("fpiarm not in a process");
-	ufp = &up->fpsave;
+	ufp = up->fpsave;
 	/*
 	 * because all the emulated fp state is in the proc structure,
 	 * it need not be saved/restored
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -3,14 +3,14 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef union FPsave	FPsave;
+typedef struct FPx87state FPx87state;
 typedef struct FPssestate FPssestate;
-typedef struct FPstate	FPstate;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
 typedef struct MMU	MMU;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct PCArch	PCArch;
 typedef struct Pcidev	Pcidev;
 typedef struct PCMmap	PCMmap;
@@ -51,23 +51,8 @@
 	ulong	pc;
 };
 
-
-/*
- * FPsave.status
- */
-enum
+struct	FPx87state		/* x87 fp state */
 {
-	/* this is a state */
-	FPinit=		0,
-	FPactive=	1,
-	FPinactive=	2,
-
-	/* the following is a bit that can be or'd into the state */
-	FPillegal=	0x100,
-};
-
-struct	FPstate
-{
 	ushort	control;
 	ushort	r1;
 	ushort	status;
@@ -98,18 +83,30 @@
 	ulong	mxcsr;		/* MXCSR register state */
 	ulong	mxcsr_mask;	/* MXCSR mask register */
 	uchar	xregs[480];	/* extended registers */
-	uchar	alignpad[FPalign];
 };
 
-/*
- * the FP regs must be stored here, not somewhere pointed to from here.
- * port code assumes this.
- */
 union FPsave {
-	FPstate;
+	FPx87state;
 	FPssestate;
 };
 
+struct PFPU
+{
+	int	fpstate;
+	FPsave	*fpsave;
+};
+
+enum
+{
+	/* this is a state */
+	FPinit=		0,
+	FPactive=	1,
+	FPinactive=	2,
+
+	/* the following is a bit that can be or'd into the state */
+	FPillegal=	0x100,
+};
+
 struct Confmem
 {
 	ulong	base;
@@ -162,16 +159,6 @@
 	
 	u32int	dr[8];			/* debug registers */
 	void	*vmx;
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave
-{
-	ulong	svflags;
-	ulong	svcs;
-	ulong	svss;
 };
 
 #include "../port/portdat.h"
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -40,9 +40,7 @@
 void	(*fprestore)(FPsave*);
 void	(*fpsave)(FPsave*);
 void	fpsserestore(FPsave*);
-void	fpsserestore0(FPsave*);
 void	fpssesave(FPsave*);
-void	fpssesave0(FPsave*);
 void	fpx87restore(FPsave*);
 void	fpx87restore0(FPsave*);
 void	fpx87save(FPsave*);
--- a/sys/src/9/pc/l.s
+++ b/sys/src/9/pc/l.s
@@ -622,13 +622,13 @@
 	FPOFF
 	RET
 
-TEXT fpssesave0(SB), $0				/* save state and disable */
+TEXT fpssesave(SB), $0				/* save state and disable */
 	MOVL	p+0(FP), AX
 	FXSAVE	0(AX)				/* no WAIT */
 	FPOFF
 	RET
 
-TEXT fpsserestore0(SB), $0			/* enable and restore state */
+TEXT fpsserestore(SB), $0			/* enable and restore state */
 	FPON
 	MOVL	p+0(FP), AX
 	FXRSTOR	0(AX)
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -311,12 +311,8 @@
 }
 
 /*
- * we keep FPsave structure in sse format emulating FXSAVE / FXRSTOR
+ * we keep FPsave structure in SSE format emulating FXSAVE / FXRSTOR
  * instructions for legacy x87 fpu.
- *
- * Note that fpx87restore() and fpxsserestore() do modify the FPsave
- * data structure for conversion / realignment shuffeling. this means
- * that p->fpsave is only valid when p->fpstate == FPinactive.
  */
 void
 fpx87save(FPsave *fps)
@@ -441,32 +437,6 @@
 	fpx87restore0(fps);
 }
 
-/*
- * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
- * so we shuffle the data up and down as needed or make copies.
- */
-void
-fpssesave(FPsave *fps)
-{
-	FPsave *afps;
-
-	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
-	fpssesave0(afps);
-	if(fps != afps)  /* not aligned? shuffle down from aligned buffer */
-		memmove(fps, afps, sizeof(FPssestate) - FPalign);
-}
-
-void
-fpsserestore(FPsave *fps)
-{
-	FPsave *afps;
-
-	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
-	if(fps != afps)  /* shuffle up to make aligned */
-		memmove(afps, fps, sizeof(FPssestate) - FPalign);
-	fpsserestore0(afps);
-}
-
 static char* mathmsg[] =
 {
 	nil,	/* handled below */
@@ -524,9 +494,9 @@
 	/*
 	 *  get floating point state to check out error
 	 */
-	fpsave(&up->fpsave);
+	fpsave(up->fpsave);
 	up->fpstate = FPinactive;
-	mathnote(up->fpsave.fsw, up->fpsave.fpuip);
+	mathnote(up->fpsave->fsw, up->fpsave->fpuip);
 }
 
 /*
@@ -535,9 +505,9 @@
 static void
 simderror(Ureg *ureg, void*)
 {
-	fpsave(&up->fpsave);
+	fpsave(up->fpsave);
 	up->fpstate = FPinactive;
-	mathnote(up->fpsave.mxcsr & 0x3f, ureg->pc);
+	mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
 }
 
 /*
@@ -558,6 +528,8 @@
 		fpinit();
 		if(fpsave == fpssesave)
 			ldmxcsr(0);	/* no simd exceptions on 386 */
+		while(up->fpsave == nil)
+			up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
 		up->fpstate = FPactive;
 		break;
 	case FPinactive:
@@ -568,13 +540,13 @@
 		 * More attention should probably be paid here to the
 		 * exception masks and error summary.
 		 */
-		status = up->fpsave.fsw;
-		control = up->fpsave.fcw;
+		status = up->fpsave->fsw;
+		control = up->fpsave->fcw;
 		if((status & ~control) & 0x07F){
-			mathnote(status, up->fpsave.fpuip);
+			mathnote(status, up->fpsave->fpuip);
 			break;
 		}
-		fprestore(&up->fpsave);
+		fprestore(up->fpsave);
 		up->fpstate = FPactive;
 		break;
 	case FPactive:
@@ -645,10 +617,12 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		while(p->fpsave == nil)
+			p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	
@@ -708,7 +682,7 @@
 			 * until the process runs again and generates an
 			 * emulation fault to activate the FPU.
 			 */
-			fpsave(&p->fpsave);
+			fpsave(p->fpsave);
 		}
 		p->fpstate = FPinactive;
 	}
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -854,7 +854,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -2,15 +2,13 @@
 typedef struct BIOS32ci	BIOS32ci;
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
-typedef union  FPsave	FPsave;
-typedef struct Fxsave	Fxsave;
-typedef struct FPstate	FPstate;
+typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
 typedef struct MMU	MMU;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct PCArch	PCArch;
 typedef struct Pcidev	Pcidev;
 typedef struct PCMmap	PCMmap;
@@ -51,25 +49,8 @@
 	uintptr	pc;
 };
 
-/*
- * FPsave.status
- */
-enum
+struct FPsave
 {
-	/* this is a state */
-	FPinit=		0,
-	FPactive=	1,
-	FPinactive=	2,
-
-	/* the following is a bit that can be or'd into the state */
-	FPillegal=	0x100,
-};
-
-/*
- * the FP regs must be stored here, not somewhere pointed to from here.
- * port code assumes this.
- */
-struct Fxsave {
 	u16int	fcw;			/* x87 control word */
 	u16int	fsw;			/* x87 status word */
 	u8int	ftw;			/* x87 tag word */
@@ -84,11 +65,23 @@
 	uchar	ign[96];		/* reserved, ignored */
 };
 
-union FPsave {
-	uchar align[512+15];
-	Fxsave;
+struct PFPU
+{
+	int	fpstate;
+	FPsave	*fpsave;
 };
 
+enum
+{
+	/* this is a state */
+	FPinit=		0,
+	FPactive=	1,
+	FPinactive=	2,
+
+	/* the following is a bit that can be or'd into the state */
+	FPillegal=	0x100,
+};
+
 struct Confmem
 {
 	uintptr	base;
@@ -147,16 +140,6 @@
 	
 	u64int	dr[8];
 	void	*vmx;
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave
-{
-	ulong	svflags;
-	ulong	svcs;
-	ulong	svss;
 };
 
 #include "../port/portdat.h"
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -392,15 +392,13 @@
  * SIMD Floating Point.
  * Assembler support to get at the individual instructions
  * is in l.s.
- * There are opportunities to be lazier about saving and
- * restoring the state and allocating the storage needed.
  */
 extern void _clts(void);
 extern void _fldcw(u16int);
 extern void _fnclex(void);
 extern void _fninit(void);
-extern void _fxrstor(Fxsave*);
-extern void _fxsave(Fxsave*);
+extern void _fxrstor(void*);
+extern void _fxsave(void*);
 extern void _fwait(void);
 extern void _ldmxcsr(u32int);
 extern void _stts(void);
@@ -418,24 +416,16 @@
 }
 
 void
-fpssesave(FPsave *fps)
+fpssesave(FPsave *s)
 {
-	Fxsave *fx = (Fxsave*)ROUND(((uintptr)fps), FPalign);
-
-	_fxsave(fx);
+	_fxsave(s);
 	_stts();
-	if(fx != (Fxsave*)fps)
-		memmove((Fxsave*)fps, fx, sizeof(Fxsave));
 }
 void
-fpsserestore(FPsave *fps)
+fpsserestore(FPsave *s)
 {
-	Fxsave *fx = (Fxsave*)ROUND(((uintptr)fps), FPalign);
-
-	if(fx != (Fxsave*)fps)
-		memmove(fx, (Fxsave*)fps, sizeof(Fxsave));
 	_clts();
-	_fxrstor(fx);
+	_fxrstor(s);
 }
 
 static char* mathmsg[] =
@@ -488,9 +478,9 @@
 	/*
 	 * Save FPU state to check out the error.
 	 */
-	fpsave(&up->fpsave);
+	fpsave(up->fpsave);
 	up->fpstate = FPinactive;
-	mathnote(up->fpsave.fsw, up->fpsave.rip);
+	mathnote(up->fpsave->fsw, up->fpsave->rip);
 }
 
 /*
@@ -499,9 +489,9 @@
 static void
 simderror(Ureg *ureg, void*)
 {
-	fpsave(&up->fpsave);
+	fpsave(up->fpsave);
 	up->fpstate = FPinactive;
-	mathnote(up->fpsave.mxcsr & 0x3f, ureg->pc);
+	mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
 }
 
 void
@@ -538,6 +528,8 @@
 	switch(up->fpstate){
 	case FPinit:
 		fpinit();
+		while(up->fpsave == nil)
+			up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
 		up->fpstate = FPactive;
 		break;
 	case FPinactive:
@@ -548,13 +540,13 @@
 		 * More attention should probably be paid here to the
 		 * exception masks and error summary.
 		 */
-		status = up->fpsave.fsw;
-		control = up->fpsave.fcw;
+		status = up->fpsave->fsw;
+		control = up->fpsave->fcw;
 		if((status & ~control) & 0x07F){
-			mathnote(status, up->fpsave.rip);
+			mathnote(status, up->fpsave->rip);
 			break;
 		}
-		fprestore(&up->fpsave);
+		fprestore(up->fpsave);
 		up->fpstate = FPactive;
 		break;
 	case FPactive:
@@ -605,10 +597,12 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		while(p->fpsave == nil)
+			p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	splx(s);
@@ -665,7 +659,7 @@
 			 * until the process runs again and generates an
 			 * emulation fault to activate the FPU.
 			 */
-			fpsave(&p->fpsave);
+			fpsave(p->fpsave);
 		}
 		p->fpstate = FPinactive;
 	}
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -823,7 +823,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -1012,7 +1012,9 @@
 		goto regread;
 
 	case Qfpregs:
-		rptr = (uchar*)&p->fpsave;
+		if(p->fpstate != FPinactive)
+			error(Enoreg);
+		rptr = (uchar*)p->fpsave;
 		rsize = sizeof(FPsave);
 	regread:
 		if(rptr == nil)
@@ -1232,7 +1234,9 @@
 			n = 0;
 		else if(offset+n > sizeof(FPsave))
 			n = sizeof(FPsave) - offset;
-		memmove((uchar*)&p->fpsave+offset, va, n);
+		if(p->fpstate != FPinactive || p->fpsave == nil)
+			error(Enoreg);
+		memmove((uchar*)p->fpsave+offset, va, n);
 		break;
 
 	case Qctl:
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -676,6 +676,8 @@
 	Fgrp	*closingfgrp;	/* used during teardown */
 
 	ulong	parentpid;
+
+	int	insyscall;
 	ulong	time[6];	/* User, Sys, Real; child U, S, R */
 
 	uvlong	kentry;		/* Kernel entry time stamp (for profiling) */
@@ -689,9 +691,6 @@
 	 */
 	vlong	pcycles;
 
-	int	insyscall;
-	int	fpstate;
-
 	QLock	debug;		/* to access debugging elements of User */
 	Proc	*pdbg;		/* the debugging process */
 	ulong	procmode;	/* proc device default file mode */
@@ -720,9 +719,8 @@
 	void	(*kpfun)(void*);
 	void	*kparg;
 
-	FPsave	fpsave;		/* address of this is known by db */
-	int	scallnr;	/* sys call number - known by db */
-	Sargs	s;		/* address of this is known by db */
+	int	scallnr;	/* sys call number */
+	Sargs	s;		/* syscall arguments */
 	int	nerrlab;
 	Label	errlab[NERR];
 	char	*syserrstr;	/* last error from a system call, errbuf0 or 1 */
@@ -766,17 +764,14 @@
 
 	void	*ureg;		/* User registers for notes */
 	void	*dbgreg;	/* User registers for devproc */
-	Notsave;
 
-	/*
-	 *  machine specific MMU
-	 */
-	PMMU;
+	PFPU;			/* machine specific fpu state */
+	PMMU;			/* machine specific mmu state */
 
 	char	*syscalltrace;	/* syscall trace */
 	
-	Watchpt	*watchpt; /* watchpoints */
-	int nwatchpt;
+	Watchpt	*watchpt;	/* watchpoints */
+	int	nwatchpt;
 };
 
 enum
--- a/sys/src/9/ppc/dat.h
+++ b/sys/src/9/ppc/dat.h
@@ -1,11 +1,12 @@
 typedef struct Conf	Conf;
+typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Imap	Imap;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct PCArch	PCArch;
 typedef struct PMMU	PMMU;
 typedef struct Page	Page;
@@ -14,6 +15,7 @@
 typedef struct Sys	Sys;
 typedef struct Ureg	Ureg;
 typedef struct Vctl	Vctl;
+typedef long		Tval;
 
 #pragma incomplete Ureg
 #pragma incomplete Imap
@@ -46,19 +48,6 @@
 };
 
 /*
- * Proc.fpstate
- */
-enum
-{
-	/* Floating point states */
-	FPinit = 0,
-	FPactive = 1,
-	FPinactive = 2,
-	/* Bit that's or-ed in during note handling (FP is illegal in note handlers) */
-	FPillegal = 0x100,
-};
-
-/*
  * This structure must agree with fpsave and fprestore asm routines
  */
 struct FPsave
@@ -73,15 +62,36 @@
 	};
 };
 
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
+enum
+{
+	/* Floating point states */
+	FPinit = 0,
+	FPactive = 1,
+	FPinactive = 2,
+	/* Bit that's or-ed in during note handling (FP is illegal in note handlers) */
+	FPillegal = 0x100,
+};
+
+struct Confmem
+{
+	ulong	base;
+	ulong	npage;
+	ulong	kbase;
+	ulong	klimit;
+};
+
 struct Conf
 {
 	ulong	nmach;		/* processors */
 	ulong	nproc;		/* processes */
-	ulong	npage0;		/* total physical pages of memory */
-	ulong	npage1;		/* total physical pages of memory */
+	Confmem	mem[2];
 	ulong	npage;		/* total physical pages of memory */
-	ulong	base0;		/* base of bank 0 */
-	ulong	base1;		/* base of bank 1 */
 	ulong	upages;		/* user page pool */
 	ulong	nimage;		/* number of page cache image headers */
 	ulong	nswap;		/* number of swap pages */
@@ -100,14 +110,6 @@
 {
 	int	mmupid;
 	Ureg	*mmureg;		/* pointer to ureg structure */
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave
-{
-	ulong	UNUSED;
 };
 
 #include "../port/portdat.h"
--- a/sys/src/9/ppc/main.c
+++ b/sys/src/9/ppc/main.c
@@ -292,7 +292,7 @@
 	p->kentry -= t;
 	if(p->fpstate == FPactive){
 		if(p->state != Moribund)
-			fpsave(&up->fpsave);
+			fpsave(up->fpsave);
 		p->fpstate = FPinactive;
 	}
 }
--- a/sys/src/9/ppc/mkfile
+++ b/sys/src/9/ppc/mkfile
@@ -101,6 +101,6 @@
 	$AS init9.s
 	$LD -l -s -R4 -o init.out init9.$O initcode.$O /power/lib/libc.a
 	{echo 'uchar initcode[]={'
-	 strip < init.out | xd -1x |
+	<init.out xd -1x |
 		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
 	 echo '};'} > init.h
--- a/sys/src/9/ppc/trap.c
+++ b/sys/src/9/ppc/trap.c
@@ -243,7 +243,7 @@
 			up->fpstate = FPactive;
 			break;
 		case FPinactive:
-			fprestore(&up->fpsave);
+			fprestore(up->fpsave);
 			up->fpstate = FPactive;
 			break;
 		case FPactive:
@@ -711,7 +711,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
--- a/sys/src/9/sgi/dat.h
+++ b/sys/src/9/sgi/dat.h
@@ -1,6 +1,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct KMap	KMap;
 typedef struct Lance	Lance;
 typedef struct Lancemem	Lancemem;
@@ -8,7 +9,6 @@
 typedef struct Lock	Lock;
 typedef struct Mach	Mach;
 typedef struct MMU	MMU;
-typedef struct Notsave	Notsave;
 typedef struct PMMU	PMMU;
 typedef struct Softtlb	Softtlb;
 typedef struct Ureg	Ureg;
@@ -73,18 +73,6 @@
 /*
  * floating point registers
  */
-enum
-{
-	/* floating point state */
-	FPinit,
-	FPactive,
-	FPinactive,
-	FPemu,
-
-	/* bit meaning floating point illegal */
-	FPillegal= 0x100,
-};
-
 enum {
 	Nfpregs		= 32,		/* floats; half as many doubles */
 };
@@ -111,20 +99,30 @@
 	int	fpcnt;			/* how many consecutive at that addr */
 };
 
-/*
- *  mmu goo in the Proc structure
- */
-struct PMMU
+struct PFPU
 {
-	int	pidonmach[MAXMACH];
+	int	fpstate;
+	FPsave	fpsave[1];
 };
 
+enum
+{
+	/* floating point state */
+	FPinit,
+	FPactive,
+	FPinactive,
+	FPemu,
+
+	/* bit meaning floating point illegal */
+	FPillegal= 0x100,
+};
+
 /*
- *  things saved in the Proc structure during a notify
+ *  mmu goo in the Proc structure
  */
-struct Notsave
+struct PMMU
 {
-	ulong	nonempty;
+	int	pidonmach[MAXMACH];
 };
 
 #include "../port/portdat.h"
--- a/sys/src/9/sgi/fptrap.c
+++ b/sys/src/9/sgi/fptrap.c
@@ -29,7 +29,7 @@
 {
 	ulong iw, npc;
 
-	if((up->fpsave.fpstatus&(1<<17)) == 0)
+	if((up->fpsave->fpstatus&(1<<17)) == 0)
 		return;
 
 	if(ur->cause & (1<<31))
@@ -41,7 +41,7 @@
 		return;
 
 	if(ur->cause & (1<<31)){
-		npc = branch(ur, up->fpsave.fpstatus);
+		npc = branch(ur, up->fpsave->fpstatus);
 		if(npc == 0)
 			return;
 		ur->pc = npc;
@@ -49,7 +49,7 @@
 	else
 		ur->pc += 4;
 
-	up->fpsave.fpstatus &= ~(1<<17);
+	up->fpsave->fpstatus &= ~(1<<17);
 }
 
 static void
@@ -107,8 +107,8 @@
 	ft = (iw>>16) & ((1<<5)-1);
 	fs = (iw>>11) & ((1<<5)-1);
 	fd = (iw>>6) & ((1<<5)-1);
-	unpack(&up->fpsave, fmt, fs, &ss, &es);
-	unpack(&up->fpsave, fmt, ft, &st, &et);
+	unpack(up->fpsave, fmt, fs, &ss, &es);
+	unpack(up->fpsave, fmt, ft, &st, &et);
 	ed = 0;
 	maxe = 0;
 	maxm = 0;
@@ -124,11 +124,11 @@
 	}
 	switch(op){
 	case ABS:
-		up->fpsave.reg[fd] &= ~0x80000000;
+		up->fpsave->reg[fd] &= ~0x80000000;
 		return 1;
 
 	case NEG:
-		up->fpsave.reg[fd] ^= 0x80000000;
+		up->fpsave->reg[fd] ^= 0x80000000;
 		return 1;
 
 	case SUB:
@@ -164,9 +164,9 @@
 		return 0;
 	}
 	if(ed <= -(maxe-5)){	/* guess: underflow */
-		zeroreg(&up->fpsave, fmt, fd, sd);
+		zeroreg(up->fpsave, fmt, fd, sd);
 		/* Set underflow exception and sticky */
-		up->fpsave.fpstatus |= (1<<3)|(1<<13);
+		up->fpsave->fpstatus |= (1<<3)|(1<<13);
 		return 1;
 	}
 	return 0;
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -396,7 +396,7 @@
 procsetup(Proc *p)
 {
 	p->fpstate = FPinit;
-	p->fpsave = initfp;
+	memmove(p->fpsave, &initfp, sizeof(FPsave));
 
 	cycles(&p->kentry);
 	p->pcycles = -p->kentry;
@@ -413,11 +413,11 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		savefpregs(&up->fpsave);
+		savefpregs(up->fpsave);
 		up->fpstate = FPinactive;
 		/* wet floor */
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	splx(s);
@@ -430,7 +430,7 @@
 
 	if(p->fpstate == FPactive){
 		if(p->state != Moribund) {
-			savefpregs(&p->fpsave);
+			savefpregs(p->fpsave);
 			p->fpstate = FPinactive;
 		}
 	}
--- a/sys/src/9/sgi/trap.c
+++ b/sys/src/9/sgi/trap.c
@@ -212,7 +212,7 @@
 		if(!user)
 			goto Default;
 		if(up->fpstate == FPactive){
-			savefpregs(&up->fpsave);
+			savefpregs(up->fpsave);
 			up->fpstate = FPinactive;
 		}
 		clrfpintr();
@@ -257,7 +257,7 @@
 				break;
 			}
 			if(up->fpstate == FPinit || up->fpstate == FPinactive){
-				restfpregs(&up->fpsave, up->fpsave.fpstatus&~FPEXPMASK);
+				restfpregs(up->fpsave, up->fpsave->fpstatus&~FPEXPMASK);
 				up->fpstate = FPactive;
 				ur->status |= CU1;
 				break;
@@ -289,7 +289,7 @@
 	}
 
 	if(fpchk) {
-		fpfcr31 = up->fpsave.fpstatus;
+		fpfcr31 = up->fpsave->fpstatus;
 		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
 			spllo();
 			fpexcep	= fpexcname(ur, fpfcr31, buf1, sizeof buf1);
@@ -501,7 +501,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		savefpregs(&up->fpsave);
+		savefpregs(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
--- a/sys/src/9/teg2/dat.h
+++ b/sys/src/9/teg2/dat.h
@@ -24,6 +24,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct ISAConf	ISAConf;
 typedef struct Isolated Isolated;
 typedef struct Label	Label;
@@ -33,7 +34,6 @@
 typedef struct MMMU	MMMU;
 typedef struct Mach	Mach;
 typedef u32int Mreg;				/* Msr - bloody UART */
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct Pcisiz Pcisiz;
 typedef struct Pcidev Pcidev;
@@ -72,14 +72,14 @@
 	uintptr	pc;
 };
 
+/*
+ * emulated or vfp3 floating point
+ */
 enum {
 	Maxfpregs	= 32,	/* could be 16 or 32, see Mach.fpnregs */
 	Nfpctlregs	= 16,
 };
 
-/*
- * emulated or vfp3 floating point
- */
 struct FPsave
 {
 	ulong	status;
@@ -94,9 +94,12 @@
 	uintptr	pc;		/* of failed fp instr. */
 };
 
-/*
- * FPsave.fpstate
- */
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
 enum
 {
 	FPinit,
@@ -133,13 +136,6 @@
 	ulong	hz;		/* processor cycle freq */
 	ulong	mhz;
 	int	monitor;	/* flag */
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave {
-	int	emptiness;
 };
 
 /*
--- a/sys/src/9/teg2/fpiarm.c
+++ b/sys/src/9/teg2/fpiarm.c
@@ -650,7 +650,7 @@
 
 	if(up == nil)
 		panic("fpiarm not in a process");
-	ufp = &up->fpsave;
+	ufp = up->fpsave;
 	/*
 	 * because all the emulated fp state is in the proc structure,
 	 * it need not be saved/restored
--- a/sys/src/9/xen/main.c
+++ b/sys/src/9/xen/main.c
@@ -450,7 +450,7 @@
 	ulong status;
 	char *msg, note[ERRMAX];
 
-	status = up->fpsave.status;
+	status = up->fpsave->status;
 
 	/*
 	 * Some attention should probably be paid here to the
@@ -473,7 +473,7 @@
 			msg = "invalid operation";
 	}
  	snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
- 		msg, up->fpsave.pc, status);
+ 		msg, up->fpsave->pc, status);
 	postnote(up, 1, note, NDebug);
 }
 
@@ -493,12 +493,12 @@
 	/*
 	 *  save floating point state to check out error
 	 */
-	fpenv(&up->fpsave);
+	fpenv(up->fpsave);
 	mathnote();
 
 	if(ur->pc & KZERO)
 		panic("fp: status %ux fppc=0x%lux pc=0x%lux",
-			up->fpsave.status, up->fpsave.pc, ur->pc);
+			up->fpsave->status, up->fpsave->pc, ur->pc);
 }
 
 /*
@@ -515,6 +515,8 @@
 	switch(up->fpstate){
 	case FPinit:
 		fpinit();
+		while(up->fpsave == nil)
+			up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
 		up->fpstate = FPactive;
 		break;
 	case FPinactive:
@@ -525,11 +527,11 @@
 		 * More attention should probably be paid here to the
 		 * exception masks and error summary.
 		 */
-		if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
+		if((up->fpsave->status & ~up->fpsave->control) & 0x07F){
 			mathnote();
 			break;
 		}
-		fprestore(&up->fpsave);
+		fprestore(up->fpsave);
 		up->fpstate = FPactive;
 		break;
 	case FPactive:
@@ -580,10 +582,12 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		while(p->fpsave == nil)
+			p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	splx(s);
@@ -622,7 +626,7 @@
 			 * until the process runs again and generates an
 			 * emulation fault to activate the FPU.
 			 */
-			fpsave(&p->fpsave);
+			fpsave(p->fpsave);
 		}
 		p->fpstate = FPinactive;
 	}
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -674,7 +674,7 @@
 	scallnr = ureg->ax;
 	up->scallnr = scallnr;
 	if(scallnr == RFORK && up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	spllo();
@@ -764,7 +764,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
--- a/sys/src/9/zynq/dat.h
+++ b/sys/src/9/zynq/dat.h
@@ -1,6 +1,7 @@
 typedef struct Conf	Conf;
 typedef struct Confmem	Confmem;
 typedef struct FPsave	FPsave;
+typedef struct PFPU	PFPU;
 typedef struct L1	L1;
 typedef struct Label	Label;
 typedef struct Lock	Lock;
@@ -7,7 +8,6 @@
 typedef struct KMap	KMap;
 typedef struct MMMU	MMMU;
 typedef struct Mach	Mach;
-typedef struct Notsave	Notsave;
 typedef struct Page	Page;
 typedef struct Proc	Proc;
 typedef struct PMMU	PMMU;
@@ -43,9 +43,12 @@
 	uchar	regs[256];
 };
 
-/*
- * FPsave.status
- */
+struct PFPU
+{
+	int	fpstate;
+	FPsave	fpsave[1];
+};
+
 enum
 {
 	FPinit,
@@ -77,13 +80,6 @@
 	ulong	nswap;		/* number of swap pages */
 	int	nswppo;		/* max # of pageouts per segment pass */
 	int	monitor;
-};
-
-/*
- *  things saved in the Proc structure during a notify
- */
-struct Notsave {
-	int	emptiness;
 };
 
 /*
--- a/sys/src/9/zynq/main.c
+++ b/sys/src/9/zynq/main.c
@@ -50,10 +50,10 @@
 	s = splhi();
 	switch(up->fpstate & ~FPillegal){
 	case FPactive:
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	case FPinactive:
-		p->fpsave = up->fpsave;
+		memmove(p->fpsave, up->fpsave, sizeof(FPsave));
 		p->fpstate = FPinactive;
 	}
 	splx(s);
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -134,7 +134,7 @@
 		break;
 	case FPinactive:
 		s = splhi();
-		fprestore(&up->fpsave);
+		fprestore(up->fpsave);
 		up->fpstate = FPactive;
 		splx(s);
 		break;
@@ -304,7 +304,7 @@
 		return 0;
 
 	if(up->fpstate == FPactive){
-		fpsave(&up->fpsave);
+		fpsave(up->fpsave);
 		up->fpstate = FPinactive;
 	}
 	up->fpstate |= FPillegal;
@@ -517,7 +517,7 @@
 		if(p->state == Moribund)
 			fpclear();
 		else
-			fpsave(&p->fpsave);
+			fpsave(p->fpsave);
 		p->fpstate = FPinactive;
 	}
 	cycles(&t);