diff 1348c68ccfadf992d57f9d7bc69d12cc0ec96963 uncommitted
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -83,10 +83,11 @@
 	FPinactive,
 	FPprotected,
 
-	FPillegal=	0x100,	/* fp forbidden in note handler */
+	FPnotify	=	0x100,	/* fp in note handler */
 };
 
 #define KFPSTATE
+#define OFPSTATE
 
 struct PFPU
 {
@@ -93,6 +94,7 @@
 	int	fpstate;
 	int	kfpstate;
 	FPsave	*fpsave;
+	FPsave	*ofpsave;
 	FPsave	*kfpsave;
 };
 
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -41,6 +41,8 @@
 void	fpuprocrestore(Proc*);
 void	fpuprocsave(Proc*);
 void	fpuprocsetup(Proc*);
+void	fpunotify(Proc*);
+void	fpunoted(Proc*);
 
 u64int	getcr0(void);
 u64int	getcr2(void);
--- a/sys/src/9/pc64/fpu.c
+++ b/sys/src/9/pc64/fpu.c
@@ -274,7 +274,7 @@
 	int s;
 
 	s = splhi();
-	switch(up->fpstate & ~FPillegal){
+	switch(up->fpstate & ~FPnotify){
 	case FPprotected:
 		_clts();
 		/* wet floor */
@@ -300,8 +300,9 @@
 			_stts();
 		}
 		fpfree(p->fpsave);
+		fpfree(p->ofpsave);
 		fpfree(p->kfpsave);
-		p->fpsave = p->kfpsave = nil;
+		p->fpsave = p->ofpsave = p->kfpsave = nil;
 		p->fpstate = p->kfpstate = FPinit;
 		return;
 	}
@@ -420,6 +421,30 @@
 		up->kfpstate = FPinactive;
 }
 
+void
+fpunotify(Proc *p)
+{
+	assert(p->ofpsave == nil);
+	fpuprocsave(p);
+	p->fpstate |= FPnotify;
+}
+
+void
+fpunoted(Proc *p)
+{
+	if(p->fpstate & FPnotify) {
+		p->fpstate &= ~FPnotify;
+	} else if(p->ofpsave != nil) {
+		fpfree(p->fpsave);
+		p->fpsave = p->ofpsave;
+		p->ofpsave = nil;
+		p->fpstate = FPinactive;
+	} else {
+		p->fpstate = FPinit;
+	}
+	assert(p->ofpsave == nil);
+}
+
 /*
  *  Before restoring the state, check for any pending
  *  exceptions, there's no way to restore the state without
@@ -489,11 +514,10 @@
 		return;
 	}
 
-	if(up->fpstate & FPillegal){
-		postnote(up, 1, "sys: floating point in note handler", NDebug);
-		return;
-	}
 	switch(up->fpstate){
+	case FPinit|FPnotify:
+		assert(up->ofpsave == nil);
+		/* wet floor */
 	case FPinit:
 		if(up->fpsave == nil)
 			up->fpsave = fpalloc();
@@ -500,6 +524,12 @@
 		up->fpstate = FPactive;
 		fpinit();
 		break;
+	case FPinactive|FPnotify:
+		assert(up->ofpsave == nil);
+		up->ofpsave = fpalloc();
+		memmove(up->ofpsave, up->fpsave, sizeof(FPsave));
+		up->fpstate &= ~FPnotify;
+		/* wet floor */
 	case FPinactive:
 		if(fpcheck(up->fpsave, 0))
 			break;
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -525,7 +525,7 @@
 
 		noted(ureg, *((ulong*)up->s.args));
 		splhi();
-		up->fpstate &= ~FPillegal;
+		fpunoted(up);
 	}
 	else
 		splhi();
@@ -597,8 +597,7 @@
 	ureg->ss = UDSEL;
 	qunlock(&up->debug);
 	splhi();
-	fpuprocsave(up);
-	up->fpstate |= FPillegal;
+	fpunotify(up);
 	return 1;
 }
 
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -18,6 +18,9 @@
 	Qctl,
 	Qfd,
 	Qfpregs,
+#ifdef OFPSTATE
+	Qofpregs,
+#endif
 #ifdef KFPSTATE
 	Qkfpregs,
 #endif
@@ -89,6 +92,9 @@
 	"ctl",		{Qctl},		0,			0000,
 	"fd",		{Qfd},		0,			0444,
 	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,
+#ifdef OFPSTATE
+	"ofpregs",	{Qofpregs},	sizeof(FPsave),		0000,
+#endif
 #ifdef KFPSTATE
 	"kfpregs",	{Qkfpregs},	sizeof(FPsave),		0400,
 #endif
@@ -455,6 +461,9 @@
 	case Qmem:
 	case Qregs:
 	case Qfpregs:
+#ifdef OFPSTATE
+	case Qofpregs:
+#endif
 	case Qprofile:
 	case Qsyscall:	
 	case Qwatchpt:
@@ -984,6 +993,12 @@
 		rsize = sizeof(FPsave);
 		goto regread;
 #endif
+#ifdef OFPSTATE
+	case Qofpregs:
+		rptr = (uchar*)p->ofpsave;
+		rsize = sizeof(FPsave);
+		goto regread;
+#endif
 	case Qfpregs:
 		if(p->fpstate != FPinactive)
 			error(Enoreg);
@@ -1167,6 +1182,7 @@
 {
 	char buf[ERRMAX];
 	ulong offset;
+	uchar *rptr;
 	Proc *p;
 
 	offset = off;
@@ -1220,13 +1236,20 @@
 		break;
 
 	case Qfpregs:
+		rptr = (uchar*)p->fpsave;
+		goto writefpreg;
+#ifdef OFPSTATE
+	case Qofpregs:
+		rptr = (uchar*)p->ofpsave;
+#endif
+writefpreg:
 		if(offset >= sizeof(FPsave))
 			n = 0;
 		else if(offset+n > sizeof(FPsave))
 			n = sizeof(FPsave) - offset;
-		if(p->fpstate != FPinactive || p->fpsave == nil)
+		if(rptr == nil)
 			error(Enoreg);
-		memmove((uchar*)p->fpsave+offset, va, n);
+		memmove(rptr+offset, va, n);
 		break;
 
 	case Qctl:
