ref: cf00494038eb41f37ff22c13fbef80ef65fbf281
parent: 3269ee741eab76bd486b178af66499800acc7efb
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Apr 5 18:55:17 EDT 2025
kernel: allow use of fpu in note handlers Instead of making it illegal to use FPU in note-handler, we save, disable and mark the fpstate with FPnotify. Once in emu-trap, we call notefpsave() which will make a copy of the original register state once the note-handler returns (which is also exposed as /proc/n/notefpregs). This patch applies to arm64, amd64, 386 and most arm32 kernels. The remaining kernels are left as an exercise to the reader.
--- a/sys/man/3/proc
+++ b/sys/man/3/proc
@@ -10,9 +10,11 @@
.BI /proc/ n /ctl
.BI /proc/ n /fd
.BI /proc/ n /fpregs
+.BI /proc/ n /kfpregs
.BI /proc/ n /kregs
.BI /proc/ n /mem
.BI /proc/ n /note
+.BI /proc/ n /notefpregs
.BI /proc/ n /noteid
.BI /proc/ n /notepg
.BI /proc/ n /ns
@@ -64,13 +66,21 @@
The files
.BR regs ,
.BR fpregs ,
+.BR kfpregs ,
+.B kregs
and
-.BR kregs
+.B notefpregs
hold representations of the user-level registers, floating-point registers,
and kernel registers in machine-dependent form.
The
.B kregs
-file is read-only.
+and
+.B kfpregs
+files are read-only.
+The
+.B notefpregs
+file holds the saved and to be restored floating-point registers
+while the program is executing its note handler.
.PP
The read-only
.B fd
--- a/sys/src/9/arm64/dat.h
+++ b/sys/src/9/arm64/dat.h
@@ -20,6 +20,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -74,6 +75,13 @@
ulong status;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link; /* when context nests */
+};
+
#define KFPSTATE
struct PFPU
@@ -80,8 +88,8 @@
{
int fpstate;
int kfpstate;
- FPsave *fpsave;
- FPsave *kfpsave;
+ FPalloc *fpsave;
+ FPalloc *kfpsave;
};
enum
@@ -88,11 +96,11 @@
{
FPinit,
FPactive,
- FPinactive,
FPprotected,
+ FPinactive, /* fpsave valid when fpstate >= FPincative */
/* bits or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
@@ -158,7 +166,7 @@
PMach;
int fpstate;
- FPsave *fpsave;
+ FPalloc *fpsave;
int cputype;
ulong delayloop;
--- a/sys/src/9/arm64/fns.h
+++ b/sys/src/9/arm64/fns.h
@@ -93,8 +93,10 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPsave* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPsave*);
+extern FPalloc* fpukenter(Ureg*);
+extern void fpukexit(Ureg*, FPalloc*);
+extern void fpunotify(Proc*);
+extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
/* trap */
--- a/sys/src/9/arm64/fpu.c
+++ b/sys/src/9/arm64/fpu.c
@@ -47,23 +47,24 @@
fpoff();
}
-static FPsave*
-fpalloc(void)
+static FPalloc*
+fpalloc(FPalloc *link)
{
- FPsave *save;
+ FPalloc *a;
- while((save = mallocalign(sizeof(FPsave), 16, 0, 0)) == nil){
- spllo();
- resrcwait("no memory for FPsave");
- splhi();
+ while((a = mallocalign(sizeof(FPalloc), 16, 0, 0)) == nil){
+ int x = spllo();
+ resrcwait("no memory for FPalloc");
+ splx(x);
}
- return save;
+ a->link = link;
+ return a;
}
static void
-fpfree(FPsave *save)
+fpfree(FPalloc *a)
{
- free(save);
+ free(a);
}
@@ -74,7 +75,7 @@
* are handled between fpukenter() and fpukexit(),
* so they can use floating point and vector instructions.
*/
-FPsave*
+FPalloc*
fpukenter(Ureg*)
{
if(up == nil){
@@ -110,7 +111,7 @@
}
void
-fpukexit(Ureg *ureg, FPsave *save)
+fpukexit(Ureg *ureg, FPalloc *o)
{
if(up == nil){
switch(m->fpstate){
@@ -121,8 +122,8 @@
fpfree(m->fpsave);
m->fpstate = FPinit;
}
- m->fpsave = save;
- if(save != nil)
+ m->fpsave = o;
+ if(o != nil)
m->fpstate = FPinactive;
return;
}
@@ -143,8 +144,8 @@
fpfree(up->kfpsave);
up->kfpstate = FPinit;
}
- up->kfpsave = save;
- if(save != nil)
+ up->kfpsave = o;
+ if(o != nil)
up->kfpstate = FPinactive;
}
@@ -151,7 +152,13 @@
void
fpuprocsetup(Proc *p)
{
+ FPalloc *a;
+
p->fpstate = FPinit;
+ while((a = p->fpsave) != nil) {
+ p->fpsave = a->link;
+ fpfree(a);
+ }
}
void
@@ -160,7 +167,7 @@
int s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPprotected:
fpon();
/* wet floor */
@@ -170,7 +177,7 @@
/* wet floor */
case FPinactive:
if(p->fpsave == nil)
- p->fpsave = fpalloc();
+ p->fpsave = fpalloc(nil);
memmove(p->fpsave, up->fpsave, sizeof(FPsave));
p->fpstate = FPinactive;
}
@@ -181,12 +188,19 @@
fpuprocsave(Proc *p)
{
if(p->state == Moribund){
+ FPalloc *a;
+
if(p->fpstate == FPactive || p->kfpstate == FPactive)
fpoff();
- fpfree(p->fpsave);
- fpfree(p->kfpsave);
- p->fpsave = p->kfpsave = nil;
p->fpstate = p->kfpstate = FPinit;
+ while((a = p->fpsave) != nil) {
+ p->fpsave = a->link;
+ fpfree(a);
+ }
+ while((a = p->kfpsave) != nil) {
+ p->kfpsave = a->link;
+ fpfree(a);
+ }
return;
}
if(p->kfpstate == FPactive){
@@ -221,6 +235,42 @@
}
void
+fpunotify(Proc *p)
+{
+ fpuprocsave(p);
+ p->fpstate |= FPnotify;
+}
+
+void
+fpunoted(Proc *p)
+{
+ FPalloc *o;
+
+ if(p->fpstate & FPnotify) {
+ p->fpstate &= ~FPnotify;
+ } else if((o = p->fpsave->link) != nil) {
+ fpfree(p->fpsave);
+ p->fpsave = o;
+ p->fpstate = FPinactive;
+ } else {
+ p->fpstate = FPinit;
+ }
+}
+
+FPsave*
+notefpsave(Proc *p)
+{
+ if(p->fpsave == nil)
+ return nil;
+ if(p->fpstate == (FPinactive|FPnotify)){
+ p->fpsave = fpalloc(p->fpsave);
+ memmove(p->fpsave, p->fpsave->link, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->fpsave->link;
+}
+
+void
mathtrap(Ureg *ureg)
{
if(!userureg(ureg)){
@@ -227,7 +277,7 @@
if(up == nil){
switch(m->fpstate){
case FPinit:
- m->fpsave = fpalloc();
+ m->fpsave = fpalloc(m->fpsave);
m->fpstate = FPactive;
fpinit();
break;
@@ -249,7 +299,7 @@
switch(up->kfpstate){
case FPinit:
- up->kfpsave = fpalloc();
+ up->kfpsave = fpalloc(up->kfpsave);
up->kfpstate = FPactive;
fpinit();
break;
@@ -263,17 +313,22 @@
return;
}
- if(up->fpstate & FPillegal){
- postnote(up, 1, "sys: floating point in note handler", NDebug);
- return;
- }
switch(up->fpstate){
+ case FPinit|FPnotify:
+ /* wet floor */
case FPinit:
if(up->fpsave == nil)
- up->fpsave = fpalloc();
+ up->fpsave = fpalloc(nil);
up->fpstate = FPactive;
fpinit();
break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
case FPinactive:
fprestore(up->fpsave);
up->fpstate = FPactive;
--- a/sys/src/9/arm64/trap.c
+++ b/sys/src/9/arm64/trap.c
@@ -97,7 +97,7 @@
void
trap(Ureg *ureg)
{
- FPsave *f = nil;
+ FPalloc *f = nil;
u32int type, intr;
int user;
@@ -265,13 +265,9 @@
* to it when returning form syscall()
*/
returnto(noteret);
-
- splhi();
- up->fpstate &= ~FPillegal;
}
- else
- splhi();
+ splhi();
if(scallnr != RFORK && (up->procctl || up->nnote))
notify(ureg);
@@ -329,11 +325,11 @@
ureg->sp = sp;
ureg->pc = (uintptr) up->notify;
ureg->link = 0;
- qunlock(&up->debug);
splhi();
- fpuprocsave(up);
- up->fpstate |= FPillegal;
+ fpunotify(up);
+ qunlock(&up->debug);
+
return 1;
}
@@ -350,7 +346,11 @@
pexit("Suicide", 0);
}
up->notified = 0;
-
+
+ splhi();
+ fpunoted(up);
+ spllo();
+
nureg = up->ureg;
oureg = (uintptr) nureg;
--- a/sys/src/9/bcm/dat.h
+++ b/sys/src/9/bcm/dat.h
@@ -14,6 +14,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -74,8 +75,14 @@
* each must be able to hold an Internal from fpi.h for sw emulation.
*/
ulong regs[Maxfpregs][3];
+};
- int fpstate;
+struct FPalloc
+{
+ FPsave;
+
+ /* the following fields are not visible to devproc */
+ int fpstate; /* FPinactive or FPemu */
uintptr pc; /* of failed fp instr. */
};
@@ -82,7 +89,8 @@
struct PFPU
{
int fpstate;
- FPsave fpsave[1];
+ FPalloc *fpsave;
+ FPalloc *ofpsave;
};
enum
@@ -89,11 +97,11 @@
{
FPinit,
FPactive,
- FPinactive,
+ FPinactive, /* fpsave valid when fpstate >= FPincative */
FPemu,
/* bits or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
--- a/sys/src/9/bcm/fns.h
+++ b/sys/src/9/bcm/fns.h
@@ -109,14 +109,16 @@
*/
extern int fpiarm(Ureg*);
extern int fpudevprocio(Proc*, void*, long, uintptr, int);
+extern FPalloc *fpalloc(void);
extern void fpuinit(void);
extern void fpunoted(void);
-extern void fpunotify(Ureg*);
+extern void fpunotify(void);
extern void fpuprocrestore(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocfork(Proc*);
extern void fpusysprocsetup(Proc*);
extern int fpuemu(Ureg*);
+
/*
* Things called from port.
*/
--- a/sys/src/9/bcm/fpiarm.c
+++ b/sys/src/9/bcm/fpiarm.c
@@ -644,7 +644,7 @@
fpiarm(Ureg *ur)
{
ulong op, o, cp;
- FPsave *ufp;
+ FPalloc *ufp;
int n;
void (*fpemu)(ulong , ulong , Ureg *, FPsave *);
@@ -651,21 +651,28 @@
if(up == nil)
panic("fpiarm not in a process");
ufp = up->fpsave;
- /*
- * because all the emulated fp state is in the proc structure,
- * it need not be saved/restored
- */
switch(up->fpstate){
case FPactive:
case FPinactive:
+ case FPinactive|FPnotify:
error("illegal instruction: emulated fpu opcode in VFP mode");
case FPinit:
- assert(sizeof(Internal) <= sizeof(ufp->regs[0]));
- up->fpstate = FPemu;
+ case FPinit|FPnotify:
+ if(ufp == nil)
+ ufp = fpalloc();
+ ufp->fpstate = FPemu;
ufp->control = 0;
ufp->status = (0x01<<28)|(1<<12); /* sw emulation, alt. C flag */
for(n = 0; n < Nfpctlregs; n++)
FR(ufp, n) = fpconst[0];
+ up->fpsave = ufp;
+ up->fpstate = FPemu;
+ break;
+ case FPemu|FPnotify:
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ break;
}
for(n=0; ;n++){
validaddr(ur->pc, 4, 0);
--- a/sys/src/9/bcm/softfpu.c
+++ /dev/null
@@ -1,1 +1,0 @@
-#include "../teg2/softfpu.c"
--- a/sys/src/9/bcm/vfp3.c
+++ b/sys/src/9/bcm/vfp3.c
@@ -213,6 +213,17 @@
fpwr(Fpexc, fprd(Fpexc) & ~Fpmbc);
}
+FPalloc*
+fpalloc(void)
+{
+ FPalloc *f;
+ while((f = mallocalign(sizeof(FPalloc), 16, 0, 0)) == nil){
+ int x = spllo();
+ resrcwait("no memory for FPalloc");
+ splx(x);
+ }
+ return f;
+}
/*
* Called when a note is about to be delivered to a
@@ -222,13 +233,13 @@
* checked in the Device Not Available handler.
*/
void
-fpunotify(Ureg*)
+fpunotify(void)
{
if(up->fpstate == FPactive){
fpsave(up->fpsave);
- up->fpstate = FPinactive;
+ up->fpstate = up->fpsave->fpstate = FPinactive;
}
- up->fpstate |= FPillegal;
+ up->fpstate |= FPnotify;
}
/*
@@ -239,9 +250,37 @@
void
fpunoted(void)
{
- up->fpstate &= ~FPillegal;
+ if(up->fpstate & FPnotify){
+ up->fpstate &= ~FPnotify;
+ } else {
+ FPalloc *o;
+
+ if(up->fpstate == FPactive)
+ fpoff();
+ if((o = up->ofpsave) != nil) {
+ up->ofpsave = nil;
+ free(up->fpsave);
+ up->fpsave = o;
+ up->fpstate = o->fpstate;
+ } else {
+ up->fpstate = FPinit;
+ }
+ }
}
+FPsave*
+notefpsave(Proc *p)
+{
+ switch(p->fpstate){
+ case FPinactive|FPnotify:
+ case FPemu|FPnotify:
+ p->ofpsave = fpalloc();
+ memmove(p->ofpsave, p->fpsave, sizeof(FPalloc));
+ p->fpstate &= ~FPnotify;
+ }
+ return p->ofpsave;
+}
+
/* should only be called if p->fpstate == FPactive */
void
fpsave(FPsave *fps)
@@ -279,21 +318,24 @@
void
fpuprocsave(Proc *p)
{
- if(p->fpstate == FPactive){
- if(p->state == Moribund)
+ if(p->state == Moribund){
+ if(p->fpstate == FPactive)
fpoff();
- else{
- /*
- * Fpsave() stores without handling pending
- * unmasked exeptions. Postnote() can't be called
- * so the handling of pending exceptions is delayed
- * until the process runs again and generates an
- * emulation fault to activate the FPU.
- */
- fpsave(p->fpsave);
+ p->fpstate = FPinit;
+ if(p->fpsave != nil){
+ free(p->fpsave);
+ p->fpsave = nil;
}
- p->fpstate = FPinactive;
+ if(p->ofpsave != nil){
+ free(p->ofpsave);
+ p->ofpsave = nil;
+ }
+ return;
}
+ if(p->fpstate == FPactive){
+ fpsave(p->fpsave);
+ p->fpstate = p->fpsave->fpstate = FPinactive;
+ }
}
/*
@@ -317,14 +359,17 @@
int s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPactive:
fpsave(up->fpsave);
- up->fpstate = FPinactive;
+ up->fpstate = up->fpsave->fpstate = FPinactive;
/* no break */
case FPinactive:
- memmove(p->fpsave, up->fpsave, sizeof(FPsave));
- p->fpstate = FPinactive;
+ case FPemu:
+ if(p->fpsave == nil)
+ p->fpsave = fpalloc();
+ memmove(p->fpsave, up->fpsave, sizeof(FPalloc));
+ p->fpstate = up->fpsave->fpstate;
}
splx(s);
}
@@ -343,6 +388,15 @@
p->fpstate = FPinit;
fpoff();
splx(s);
+
+ if(p->fpsave != nil){
+ free(p->fpsave);
+ p->fpsave = nil;
+ }
+ if(p->ofpsave != nil){
+ free(p->ofpsave);
+ p->ofpsave = nil;
+ }
}
static void
@@ -379,11 +433,22 @@
{
switch(up->fpstate){
case FPemu:
+ case FPemu|FPnotify:
error("illegal instruction: VFP opcode in emulated mode");
case FPinit:
+ case FPinit|FPnotify:
+ if(up->fpsave == nil)
+ up->fpsave = fpalloc();
fpinit();
up->fpstate = FPactive;
break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
case FPinactive:
/*
* Before restoring the state, check for any pending
@@ -476,7 +541,6 @@
{
int s, nfp, cop, op;
uintptr pc;
- static int already;
if(waserror()){
postnote(up, 1, up->errstr, NDebug);
@@ -483,9 +547,6 @@
return 1;
}
- if(up->fpstate & FPillegal)
- error("floating point in note handler");
-
nfp = 0;
pc = ureg->pc;
validaddr(pc, 4, 0);
@@ -495,8 +556,6 @@
fpstuck(pc); /* debugging; could move down 1 line */
if (ISFPAOP(cop, op)) { /* old arm 7500 fpa opcode? */
s = spllo();
- if(!already++)
- pprint("warning: emulated arm7500 fpa instr %#8.8lux at %#p\n", *(ulong *)pc, pc);
if(waserror()){
splx(s);
nexterror();
--- a/sys/src/9/bcm64/dat.h
+++ b/sys/src/9/bcm64/dat.h
@@ -14,6 +14,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -68,6 +69,13 @@
ulong status;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link; /* when context nests */
+};
+
#define KFPSTATE
struct PFPU
@@ -74,8 +82,8 @@
{
int fpstate;
int kfpstate;
- FPsave *fpsave;
- FPsave *kfpsave;
+ FPalloc *fpsave;
+ FPalloc *kfpsave;
};
enum
@@ -86,7 +94,7 @@
FPprotected,
/* bits or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
@@ -154,7 +162,7 @@
PMach;
int fpstate;
- FPsave *fpsave;
+ FPalloc *fpsave;
int cputype;
ulong delayloop;
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -92,8 +92,10 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPsave* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPsave*);
+extern FPalloc* fpukenter(Ureg*);
+extern void fpukexit(Ureg*, FPalloc*);
+extern void fpunotify(Proc*);
+extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
/* trap */
--- a/sys/src/9/cycv/dat.h
+++ b/sys/src/9/cycv/dat.h
@@ -55,7 +55,7 @@
FPinit,
FPactive,
FPinactive,
- FPillegal = 0x100
+ FPnotify = 0x100
};
struct Confmem
--- a/sys/src/9/cycv/main.c
+++ b/sys/src/9/cycv/main.c
@@ -49,7 +49,7 @@
ulong s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPactive:
fpsave(up->fpsave);
up->fpstate = FPinactive;
--- a/sys/src/9/cycv/trap.c
+++ b/sys/src/9/cycv/trap.c
@@ -121,7 +121,7 @@
{
int s;
- if((up->fpstate & FPillegal) != 0){
+ if(up->fpstate & FPnotify){
postnote(up, 1, "sys: floating point in note handler", NDebug);
return;
}
@@ -278,10 +278,32 @@
kexit(ureg);
}
+void
+fpunotify(void)
+{
+ if(up->fpstate == FPactive){
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPnotify;
+}
+
+void
+fpunoted(void)
+{
+ up->fpstate &= ~FPnotify;
+}
+
+FPsave*
+notefpsave(Proc*)
+{
+ return nil;
+}
+
int
notify(Ureg *ureg)
{
- ulong s, sp;
+ ulong sp;
char *msg;
if(up->procctl)
@@ -289,13 +311,7 @@
if(up->nnote == 0)
return 0;
- if(up->fpstate == FPactive){
- fpsave(up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -329,8 +345,10 @@
ureg->sp = sp;
ureg->pc = (uintptr) up->notify;
ureg->r14 = 0;
+
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
return 1;
}
@@ -347,10 +365,12 @@
pexit("Suicide", 0);
}
up->notified = 0;
+
+ splhi();
+ fpunoted();
+ spllo();
nureg = up->ureg;
- up->fpstate &= ~FPillegal;
-
oureg = (ulong) nureg;
if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
qunlock(&up->debug);
@@ -485,7 +505,7 @@
}
void
-procrestore(Proc *p)
+procrestore(Proc*)
{
}
--- a/sys/src/9/imx8/dat.h
+++ b/sys/src/9/imx8/dat.h
@@ -20,6 +20,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -74,6 +75,13 @@
ulong status;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link; /* when context nests */
+};
+
#define KFPSTATE
struct PFPU
@@ -80,8 +88,8 @@
{
int fpstate;
int kfpstate;
- FPsave *fpsave;
- FPsave *kfpsave;
+ FPalloc *fpsave;
+ FPalloc *kfpsave;
};
enum
@@ -92,7 +100,7 @@
FPprotected,
/* bits or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
@@ -160,7 +168,7 @@
PMach;
int fpstate;
- FPsave *fpsave;
+ FPalloc *fpsave;
int cputype;
ulong delayloop;
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -95,8 +95,10 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPsave* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPsave*);
+extern FPalloc* fpukenter(Ureg*);
+extern void fpukexit(Ureg*, FPalloc*);
+extern void fpunotify(Proc*);
+extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
/* trap */
--- a/sys/src/9/kw/dat.h
+++ b/sys/src/9/kw/dat.h
@@ -73,7 +73,7 @@
FPactive,
FPinactive,
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
--- a/sys/src/9/kw/fns.h
+++ b/sys/src/9/kw/fns.h
@@ -91,7 +91,7 @@
extern int fpudevprocio(Proc*, void*, long, uintptr, int);
extern void fpuinit(void);
extern void fpunoted(void);
-extern void fpunotify(Ureg*);
+extern void fpunotify(void);
extern void fpuprocrestore(Proc*);
extern void fpuprocsave(Proc*);
extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/kw/softfpu.c
+++ b/sys/src/9/kw/softfpu.c
@@ -20,7 +20,7 @@
}
void
-fpunotify(Ureg*)
+fpunotify(void)
{
/*
* Called when a note is about to be delivered to a
@@ -39,6 +39,12 @@
* noted() routine.
* Clear the flag set above in fpunotify().
*/
+}
+
+FPsave*
+notefpsave(Proc*)
+{
+ return nil;
}
void
--- a/sys/src/9/kw/syscall.c
+++ b/sys/src/9/kw/syscall.c
@@ -36,7 +36,10 @@
pexit("Suicide", 0);
}
up->notified = 0;
+
+ splhi();
fpunoted();
+ spllo();
nf = up->ureg;
@@ -98,7 +101,6 @@
int
notify(Ureg* ureg)
{
- u32int s;
uintptr sp;
NFrame *nf;
char *msg;
@@ -108,9 +110,7 @@
if(up->nnote == 0)
return 0;
- fpunotify(ureg);
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -145,8 +145,9 @@
ureg->pc = (uintptr)up->notify;
ureg->r0 = (uintptr)nf->arg0;
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
return 1;
}
--- a/sys/src/9/lx2k/dat.h
+++ b/sys/src/9/lx2k/dat.h
@@ -20,6 +20,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -74,6 +75,13 @@
ulong status;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link; /* when context nests */
+};
+
#define KFPSTATE
struct PFPU
@@ -80,8 +88,8 @@
{
int fpstate;
int kfpstate;
- FPsave *fpsave;
- FPsave *kfpsave;
+ FPalloc *fpsave;
+ FPalloc *kfpsave;
};
enum
@@ -92,7 +100,7 @@
FPprotected,
/* bits or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
@@ -160,7 +168,7 @@
PMach;
int fpstate;
- FPsave *fpsave;
+ FPalloc *fpsave;
int cputype;
ulong delayloop;
--- a/sys/src/9/lx2k/fns.h
+++ b/sys/src/9/lx2k/fns.h
@@ -95,8 +95,10 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPsave* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPsave*);
+extern FPalloc* fpukenter(Ureg*);
+extern void fpukexit(Ureg*, FPalloc*);
+extern void fpunotify(Proc*);
+extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
/* trap */
--- a/sys/src/9/mt7688/dat.h
+++ b/sys/src/9/mt7688/dat.h
@@ -130,11 +130,11 @@
/* floating point state */
FPinit,
FPactive,
- FPinactive,
+ FPinactive, /* fpsave valid when fpstate >= FPincative */
FPemu,
- /* bit meaning floating point illegal */
- FPillegal= 0x100,
+ /* bit meaning floating point in note handler */
+ FPnotify = 0x100,
};
/*
--- a/sys/src/9/mt7688/fns.h
+++ b/sys/src/9/mt7688/fns.h
@@ -42,7 +42,6 @@
ulong rdcompare(void);
ulong rdcount(void);
ulong* reg(Ureg*, int);
-void restfpregs(FPsave*, ulong);
void intrenable(int, void(*)(Ureg *, void *), void *, int, char*);
void intrdisable(int, void (*)(Ureg*, void *), void*, int, char*);
void screeninit(void);
--- a/sys/src/9/mt7688/fpimips.c
+++ b/sys/src/9/mt7688/fpimips.c
@@ -1289,7 +1289,7 @@
return -1;
}
- if(up->fpstate & FPillegal)
+ if(up->fpstate & FPnotify)
error("floating point in note handler");
if(up->fpsave->fpdelayexec)
panic("fpuemu: entered with outstanding watch trap");
--- a/sys/src/9/mt7688/main.c
+++ b/sys/src/9/mt7688/main.c
@@ -31,7 +31,7 @@
static void
checkconf0(void)
{
- iprint("frc0 check = %uX \n", getfcr0);
+ iprint("frc0 check = %p\n", getfcr0);
// for debug stuff
}
@@ -110,8 +110,6 @@
void
main(void)
{
- savefpregs(&initfp);
-
uartconsinit();
quotefmtinstall();
--- a/sys/src/9/mt7688/syscall.c
+++ b/sys/src/9/mt7688/syscall.c
@@ -118,11 +118,27 @@
}
+void
+fpunotify(void)
+{
+ up->fpstate |= FPnotify;
+}
+void
+fpunoted(void)
+{
+ up->fpstate &= ~FPnotify;
+}
+
+FPsave*
+notefpsave(Proc *p)
+{
+ return nil;
+}
+
int
notify(Ureg *ur)
{
- int s;
ulong sp;
char *msg;
@@ -131,17 +147,15 @@
if(up->nnote == 0)
return 0;
- s = spllo();
+ spllo();
qlock(&up->debug);
- up->fpstate |= FPillegal;
msg = popnote(ur);
if(msg == nil){
qunlock(&up->debug);
- splx(s);
+ splhi();
return 0;
}
-
sp = ur->usp - sizeof(Ureg) - BY2WD; /* spim libc */
if(!okaddr((ulong)up->notify, BY2WD, 0) ||
@@ -170,8 +184,9 @@
*/
ur->pc = (ulong)up->notify;
+ fpunotify();
qunlock(&up->debug);
- splx(s);
+ splhi();
return 1;
}
@@ -193,7 +208,7 @@
}
up->notified = 0;
- up->fpstate &= ~FPillegal;
+ fpunoted();
nur = up->ureg;
--- a/sys/src/9/mt7688/trap.c
+++ b/sys/src/9/mt7688/trap.c
@@ -195,7 +195,7 @@
case CCPU:
cop = (ur->cause>>28)&3;
if(user && up && cop == 1) {
- if(up->fpstate & FPillegal) {
+ if(up->fpstate & FPnotify) {
/* someone used floating point in a note handler */
postnote(up, 1,
"sys: floating point in note handler",
--- a/sys/src/9/omap/dat.h
+++ b/sys/src/9/omap/dat.h
@@ -91,7 +91,7 @@
FPactive,
FPinactive,
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
--- a/sys/src/9/omap/fns.h
+++ b/sys/src/9/omap/fns.h
@@ -106,7 +106,7 @@
extern int fpudevprocio(Proc*, void*, long, uintptr, int);
extern void fpuinit(void);
extern void fpunoted(void);
-extern void fpunotify(Ureg*);
+extern void fpunotify(void);
extern void fpuprocrestore(Proc*);
extern void fpuprocsave(Proc*);
extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/omap/softfpu.c
+++ b/sys/src/9/omap/softfpu.c
@@ -20,7 +20,7 @@
}
void
-fpunotify(Ureg*)
+fpunotify(void)
{
/*
* Called when a note is about to be delivered to a
@@ -39,6 +39,12 @@
* noted() routine.
* Clear the flag set above in fpunotify().
*/
+}
+
+FPsave*
+notefpsave(Proc*)
+{
+ return nil;
}
void
--- a/sys/src/9/omap/syscall.c
+++ b/sys/src/9/omap/syscall.c
@@ -36,7 +36,10 @@
pexit("Suicide", 0);
}
up->notified = 0;
+
+ splhi();
fpunoted();
+ spllo();
nf = up->ureg;
@@ -98,7 +101,6 @@
int
notify(Ureg* ureg)
{
- u32int s;
uintptr sp;
NFrame *nf;
char *msg;
@@ -108,9 +110,7 @@
if(up->nnote == 0)
return 0;
- fpunotify(ureg);
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -145,8 +145,9 @@
ureg->pc = (uintptr)up->notify;
ureg->r0 = (uintptr)nf->arg0;
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
return 1;
}
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -2,6 +2,7 @@
typedef struct BIOS32ci BIOS32ci;
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef union FPsave FPsave;
typedef struct FPx87state FPx87state;
typedef struct FPssestate FPssestate;
@@ -90,10 +91,17 @@
FPssestate;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link;
+};
+
struct PFPU
{
int fpstate;
- FPsave *fpsave;
+ FPalloc *fpsave;
};
enum
@@ -101,10 +109,10 @@
/* this is a state */
FPinit= 0,
FPactive= 1,
- FPinactive= 2,
+ FPinactive= 2, /* fpsave valid when fpstate >= FPincative */
/* the following is a bit that can be or'd into the state */
- FPillegal= 0x100,
+ FPnotify= 0x100,
};
struct Confmem
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -20,6 +20,8 @@
void fpuprocfork(Proc*);
void fpuprocsave(Proc*);
void fpuprocrestore(Proc*);
+void fpunotify(Proc*);
+void fpunoted(Proc*);
int cpuidentify(void);
void cpuidprint(void);
void (*cycles)(uvlong*);
--- a/sys/src/9/pc/fpu.c
+++ b/sys/src/9/pc/fpu.c
@@ -224,6 +224,26 @@
mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
}
+static FPalloc*
+fpalloc(FPalloc *link)
+{
+ FPalloc *a;
+
+ while((a = mallocalign(sizeof(FPalloc), FPalign, 0, 0)) == nil){
+ int x = spllo();
+ resrcwait("no memory for FPalloc");
+ splx(x);
+ }
+ a->link = link;
+ return a;
+}
+
+static void
+fpfree(FPalloc *a)
+{
+ free(a);
+}
+
/*
* math coprocessor emulation fault
*/
@@ -232,20 +252,24 @@
{
ulong status, control;
- if(up->fpstate & FPillegal){
- /* someone did floating point in a note handler */
- postnote(up, 1, "sys: floating point in note handler", NDebug);
- return;
- }
switch(up->fpstate){
+ case FPinit|FPnotify:
+ /* wet floor */
case FPinit:
+ if(up->fpsave == nil)
+ up->fpsave = fpalloc(nil);
fpinit();
if(fpsave == fpssesave)
ldmxcsr(0x1f80); /* no simd exceptions on 386 */
- while(up->fpsave == nil)
- up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
up->fpstate = FPactive;
break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
case FPinactive:
/*
* Before restoring the state, check for any pending
@@ -320,8 +344,18 @@
void
fpuprocsetup(Proc *p)
{
+ FPalloc *a;
+ int s;
+
+ s = splhi();
p->fpstate = FPinit;
fpoff();
+ splx(s);
+
+ while((a = p->fpsave) != nil) {
+ p->fpsave = a->link;
+ fpfree(a);
+ }
}
void
@@ -330,13 +364,14 @@
int s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPactive:
fpsave(up->fpsave);
up->fpstate = FPinactive;
+ /* wet floor */
case FPinactive:
- while(p->fpsave == nil)
- p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
+ if(p->fpsave == nil)
+ p->fpsave = fpalloc(nil);
memmove(p->fpsave, up->fpsave, sizeof(FPsave));
p->fpstate = FPinactive;
}
@@ -346,19 +381,27 @@
void
fpuprocsave(Proc *p)
{
- if(p->fpstate == FPactive){
- if(p->state == Moribund)
+ if(p->state == Moribund){
+ FPalloc *a;
+
+ if(p->fpstate == FPactive)
fpclear();
- else{
- /*
- * Fpsave() stores without handling pending
- * unmasked exeptions. Postnote() can't be called
- * so the handling of pending exceptions is delayed
- * until the process runs again and generates an
- * emulation fault to activate the FPU.
- */
- fpsave(p->fpsave);
+ p->fpstate = FPinit;
+ while((a = p->fpsave) != nil) {
+ p->fpsave = a->link;
+ fpfree(a);
}
+ return;
+ }
+ if(p->fpstate == FPactive){
+ /*
+ * Fpsave() stores without handling pending
+ * unmasked exeptions. Postnote() can't be called
+ * so the handling of pending exceptions is delayed
+ * until the process runs again and generates an
+ * emulation fault to activate the FPU.
+ */
+ fpsave(p->fpsave);
p->fpstate = FPinactive;
}
}
@@ -366,4 +409,44 @@
void
fpuprocrestore(Proc*)
{
+}
+
+void
+fpunotify(Proc *p)
+{
+ fpuprocsave(p);
+ p->fpstate |= FPnotify;
+}
+
+void
+fpunoted(Proc *p)
+{
+ if(p->fpstate & FPnotify){
+ p->fpstate &= ~FPnotify;
+ } else {
+ FPalloc *o;
+
+ if(p->fpstate == FPactive)
+ fpclear();
+ if((o = p->fpsave->link) != nil) {
+ fpfree(p->fpsave);
+ p->fpsave = o;
+ p->fpstate = FPinactive;
+ } else {
+ p->fpstate = FPinit;
+ }
+ }
+}
+
+FPsave*
+notefpsave(Proc *p)
+{
+ if(p->fpsave == nil)
+ return nil;
+ if(p->fpstate == (FPinactive|FPnotify)){
+ p->fpsave = fpalloc(p->fpsave);
+ memmove(p->fpsave, p->fpsave->link, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->fpsave->link;
}
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -558,7 +558,7 @@
int
notify(Ureg* ureg)
{
- ulong s, sp;
+ ulong sp;
char *msg;
if(up->procctl)
@@ -566,13 +566,7 @@
if(up->nnote == 0)
return 0;
- if(up->fpstate == FPactive){
- fpsave(up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -607,8 +601,10 @@
ureg->pc = (ulong)up->notify;
ureg->cs = UESEL;
ureg->ss = ureg->ds = ureg->es = UDSEL;
+
+ splhi();
+ fpunotify(up);
qunlock(&up->debug);
- splx(s);
return 1;
}
@@ -629,9 +625,11 @@
}
up->notified = 0;
- nureg = up->ureg; /* pointer to user returned Ureg struct */
+ splhi();
+ fpunoted(up);
+ spllo();
- up->fpstate &= ~FPillegal;
+ nureg = up->ureg; /* pointer to user returned Ureg struct */
/* sanity clause */
oureg = (ulong)nureg;
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -2,6 +2,7 @@
typedef struct Confmem Confmem;
typedef struct FPssestate FPssestate;
typedef struct FPavxstate FPavxstate;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -76,14 +77,21 @@
FPavxstate;
};
+struct FPalloc
+{
+ FPsave;
+
+ FPalloc *link; /* when context nests */
+};
+
enum
{
FPinit,
FPactive,
- FPinactive,
FPprotected,
+ FPinactive, /* fpsave valid when fpstate >= FPincative */
- FPillegal= 0x100, /* fp forbidden in note handler */
+ FPnotify = 0x100, /* fp in note handler */
};
#define KFPSTATE
@@ -92,8 +100,8 @@
{
int fpstate;
int kfpstate;
- FPsave *fpsave;
- FPsave *kfpsave;
+ FPalloc *fpsave;
+ FPalloc *kfpsave;
};
struct Confmem
@@ -204,7 +212,7 @@
char havenx;
int fpstate; /* FPU state for interrupts */
- FPsave *fpsave;
+ FPalloc *fpsave;
u64int* pml4; /* pml4 base for this processor (va) */
Tss* tss; /* tss for this processor */
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -35,13 +35,14 @@
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpinit(void);
-FPsave* fpukenter(Ureg*);
-void fpukexit(Ureg*, FPsave*);
+FPalloc*fpukenter(Ureg*);
+void fpukexit(Ureg*, FPalloc*);
void fpuprocfork(Proc*);
void fpuprocrestore(Proc*);
void fpuprocsave(Proc*);
void fpuprocsetup(Proc*);
-
+void fpunotify(Proc*);
+void fpunoted(Proc*);
u64int getcr0(void);
u64int getcr2(void);
u64int getcr3(void);
--- a/sys/src/9/pc64/fpu.c
+++ b/sys/src/9/pc64/fpu.c
@@ -243,29 +243,36 @@
_stts();
}
-static FPsave*
-fpalloc(void)
+static FPalloc*
+fpalloc(FPalloc *link)
{
- FPsave *save;
+ FPalloc *a;
- while((save = mallocalign(sizeof(FPsave), FPalign, 0, 0)) == nil){
- spllo();
- resrcwait("no memory for FPsave");
- splhi();
+ while((a = mallocalign(sizeof(FPalloc), FPalign, 0, 0)) == nil){
+ int x = spllo();
+ resrcwait("no memory for FPalloc");
+ splx(x);
}
- return save;
+ a->link = link;
+ return a;
}
static void
-fpfree(FPsave *save)
+fpfree(FPalloc *a)
{
- free(save);
+ free(a);
}
void
fpuprocsetup(Proc *p)
{
+ FPalloc *a;
+
p->fpstate = FPinit;
+ while((a = p->fpsave) != nil){
+ p->fpsave = a->link;
+ fpfree(a);
+ }
}
void
@@ -274,7 +281,7 @@
int s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPprotected:
_clts();
/* wet floor */
@@ -284,7 +291,7 @@
/* wet floor */
case FPinactive:
if(p->fpsave == nil)
- p->fpsave = fpalloc();
+ p->fpsave = fpalloc(nil);
memmove(p->fpsave, up->fpsave, sizeof(FPsave));
p->fpstate = FPinactive;
}
@@ -295,14 +302,21 @@
fpuprocsave(Proc *p)
{
if(p->state == Moribund){
+ FPalloc *a;
+
if(p->fpstate == FPactive || p->kfpstate == FPactive){
_fnclex();
_stts();
}
- fpfree(p->fpsave);
- fpfree(p->kfpsave);
- p->fpsave = p->kfpsave = nil;
p->fpstate = p->kfpstate = FPinit;
+ while((a = p->fpsave) != nil){
+ p->fpsave = a->link;
+ fpfree(a);
+ }
+ while((a = p->kfpsave) != nil){
+ p->kfpsave = a->link;
+ fpfree(a);
+ }
return;
}
if(p->kfpstate == FPactive){
@@ -344,7 +358,7 @@
* are handled between fpukenter() and fpukexit(),
* so they can use floating point and vector instructions.
*/
-FPsave*
+FPalloc*
fpukenter(Ureg *)
{
if(up == nil){
@@ -380,7 +394,7 @@
}
void
-fpukexit(Ureg *ureg, FPsave *save)
+fpukexit(Ureg *ureg, FPalloc *o)
{
if(up == nil){
switch(m->fpstate){
@@ -392,8 +406,8 @@
fpfree(m->fpsave);
m->fpstate = FPinit;
}
- m->fpsave = save;
- if(save != nil)
+ m->fpsave = o;
+ if(o != nil)
m->fpstate = FPinactive;
return;
}
@@ -415,11 +429,47 @@
fpfree(up->kfpsave);
up->kfpstate = FPinit;
}
- up->kfpsave = save;
- if(save != nil)
+ up->kfpsave = o;
+ if(o != nil)
up->kfpstate = FPinactive;
}
+void
+fpunotify(Proc *p)
+{
+ fpuprocsave(p);
+ p->fpstate |= FPnotify;
+}
+
+void
+fpunoted(Proc *p)
+{
+ FPalloc *o;
+
+ if(p->fpstate & FPnotify) {
+ p->fpstate &= ~FPnotify;
+ } else if((o = p->fpsave->link) != nil) {
+ fpfree(p->fpsave);
+ p->fpsave = o;
+ p->fpstate = FPinactive;
+ } else {
+ p->fpstate = FPinit;
+ }
+}
+
+FPsave*
+notefpsave(Proc *p)
+{
+ if(p->fpsave == nil)
+ return nil;
+ if(p->fpstate == (FPinactive|FPnotify)){
+ p->fpsave = fpalloc(p->fpsave);
+ memmove(p->fpsave, p->fpsave->link, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->fpsave->link;
+}
+
/*
* Before restoring the state, check for any pending
* exceptions, there's no way to restore the state without
@@ -451,7 +501,7 @@
if(up == nil){
switch(m->fpstate){
case FPinit:
- m->fpsave = fpalloc();
+ m->fpsave = fpalloc(m->fpsave);
m->fpstate = FPactive;
fpinit();
break;
@@ -474,7 +524,7 @@
switch(up->kfpstate){
case FPinit:
- up->kfpsave = fpalloc();
+ up->kfpsave = fpalloc(up->kfpsave);
up->kfpstate = FPactive;
fpinit();
break;
@@ -489,17 +539,22 @@
return;
}
- if(up->fpstate & FPillegal){
- postnote(up, 1, "sys: floating point in note handler", NDebug);
- return;
- }
switch(up->fpstate){
+ case FPinit|FPnotify:
+ /* wet floor */
case FPinit:
if(up->fpsave == nil)
- up->fpsave = fpalloc();
+ up->fpsave = fpalloc(nil);
up->fpstate = FPactive;
fpinit();
break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
case FPinactive:
if(fpcheck(up->fpsave, 0))
break;
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -133,7 +133,7 @@
trap(Ureg *ureg)
{
int vno, user;
- FPsave *f = nil;
+ FPalloc *f = nil;
vno = ureg->type;
user = kenter(ureg);
@@ -522,14 +522,10 @@
* to it when returning form syscall()
*/
((void**)&ureg)[-1] = (void*)noteret;
-
noted(ureg, *((ulong*)up->s.args));
- splhi();
- up->fpstate &= ~FPillegal;
}
- else
- splhi();
+ splhi();
if(scallnr != RFORK && (up->procctl || up->nnote) && notify(ureg))
((void**)&ureg)[-1] = (void*)noteret; /* loads RARG */
@@ -595,10 +591,11 @@
ureg->bp = (uintptr)up->ureg; /* arg1 passed in RARG */
ureg->cs = UESEL;
ureg->ss = UDSEL;
- qunlock(&up->debug);
+
splhi();
- fpuprocsave(up);
- up->fpstate |= FPillegal;
+ fpunotify(up);
+ qunlock(&up->debug);
+
return 1;
}
@@ -618,6 +615,10 @@
pexit("Suicide", 0);
}
up->notified = 0;
+
+ splhi();
+ fpunoted(up);
+ spllo();
nureg = up->ureg; /* pointer to user returned Ureg struct */
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -24,6 +24,7 @@
Qkregs,
Qmem,
Qnote,
+ Qnotefpregs,
Qnoteid,
Qnotepg,
Qns,
@@ -95,6 +96,7 @@
"kregs", {Qkregs}, sizeof(Ureg), 0400,
"mem", {Qmem}, 0, 0000,
"note", {Qnote}, 0, 0000,
+ "notefpregs", {Qnotefpregs}, sizeof(FPsave), 0000,
"noteid", {Qnoteid}, 0, 0664,
"notepg", {Qnotepg}, 0, 0000,
"ns", {Qns}, 0, 0444,
@@ -455,6 +457,7 @@
case Qmem:
case Qregs:
case Qfpregs:
+ case Qnotefpregs:
case Qprofile:
case Qsyscall:
case Qwatchpt:
@@ -978,16 +981,23 @@
goto regread;
#ifdef KFPSTATE
case Qkfpregs:
- if(p->kfpstate != FPinactive)
+ if(p->kfpstate < FPinactive)
error(Enoreg);
rptr = (uchar*)p->kfpsave;
- rsize = sizeof(FPsave);
- goto regread;
+ goto fpregread;
#endif
+ case Qnotefpregs:
+ if(!p->notified)
+ error(Enoreg);
+ rptr = (uchar*)notefpsave(p);
+ if(rptr != nil)
+ goto fpregread;
+ /* wet floor */
case Qfpregs:
- if(p->fpstate != FPinactive)
+ if((p->fpstate & ~FPnotify) < FPinactive)
error(Enoreg);
rptr = (uchar*)p->fpsave;
+ fpregread:
rsize = sizeof(FPsave);
regread:
if(rptr == nil)
@@ -1167,6 +1177,7 @@
{
char buf[ERRMAX];
ulong offset;
+ uchar *rptr;
Proc *p;
offset = off;
@@ -1219,14 +1230,28 @@
setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
break;
+ case Qnotefpregs:
+ if(!p->notified)
+ error(Enoreg);
+ rptr = (uchar*)notefpsave(p);
+ if(rptr != nil)
+ goto fpregwrite;
+ else {
case Qfpregs:
+ if(p->notified)
+ notefpsave(p);
+ }
+ if((p->fpstate & ~FPnotify) < FPinactive)
+ error(Enoreg);
+ rptr = (uchar*)p->fpsave;
+ fpregwrite:
+ if(rptr == nil)
+ error(Enoreg);
if(offset >= sizeof(FPsave))
n = 0;
else if(offset+n > sizeof(FPsave))
n = sizeof(FPsave) - offset;
- if(p->fpstate != FPinactive || p->fpsave == nil)
- error(Enoreg);
- memmove((uchar*)p->fpsave+offset, va, n);
+ memmove(rptr+offset, va, n);
break;
case Qctl:
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -221,6 +221,7 @@
Proc* newproc(void);
_Noreturn void nexterror(void);
int notify(Ureg*);
+FPsave* notefpsave(Proc*);
ulong nkpages(Confmem*);
uvlong ns2fastticks(uvlong);
int okaddr(uintptr, ulong, int);
@@ -325,7 +326,6 @@
long rtctime(void);
void runlock(RWlock*);
Proc* runproc(void);
-void savefpregs(FPsave*);
void sched(void);
_Noreturn void schedinit(void);
void (*screenputs)(char*, int);
--- a/sys/src/9/sgi/dat.h
+++ b/sys/src/9/sgi/dat.h
@@ -122,10 +122,10 @@
FPinit,
FPactive,
FPinactive,
- FPemu,
+ FPemu, /* fpsave valid when fpstate >= FPincative */
- /* bit meaning floating point illegal */
- FPillegal= 0x100,
+ /* bit meaning floating point in note handler */
+ FPnotify = 0x100,
};
/*
--- a/sys/src/9/sgi/fns.h
+++ b/sys/src/9/sgi/fns.h
@@ -46,6 +46,7 @@
ulong* reg(Ureg*, int);
void restfpregs(FPsave*, ulong);
void intrenable(int, void(*)(Ureg *, void *), void *);
+void savefpregs(FPsave*);
void screeninit(void);
void setpagemask(ulong);
void setwired(ulong);
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -301,7 +301,7 @@
int s;
s = splhi();
- switch(up->fpstate & ~FPillegal){
+ switch(up->fpstate & ~FPnotify){
case FPactive:
savefpregs(up->fpsave);
up->fpstate = FPinactive;
--- a/sys/src/9/sgi/trap.c
+++ b/sys/src/9/sgi/trap.c
@@ -210,7 +210,7 @@
case CCPU:
cop = (ur->cause>>28)&3;
if(user && up && cop == 1) {
- if(up->fpstate & FPillegal) {
+ if(up->fpstate & FPnotify) {
/* someone used floating point in a note handler */
postnote(up, 1,
"sys: floating point in note handler",
@@ -442,10 +442,31 @@
regname[i+1].name, R(ur, i+1));
}
+void
+fpunotify(void)
+{
+ if(up->fpstate == FPactive){
+ savefpregs(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPnotify;
+}
+
+void
+fpunoted(void)
+{
+ up->fpstate &= ~FPnotify;
+}
+
+FPsave*
+notefpsave(Proc*)
+{
+ return nil;
+}
+
int
notify(Ureg *ur)
{
- int s;
ulong sp;
char *msg;
@@ -454,18 +475,12 @@
if(up->nnote == 0)
return 0;
- if(up->fpstate == FPactive){
- savefpregs(up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ur);
if(msg == nil){
qunlock(&up->debug);
- splx(s);
+ splhi();
return 0;
}
@@ -498,8 +513,9 @@
*/
ur->pc = (ulong)up->notify;
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
return 1;
}
@@ -520,10 +536,11 @@
}
up->notified = 0;
- up->fpstate &= ~FPillegal;
+ splhi();
+ fpunoted();
+ spllo();
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");
--- a/sys/src/9/teg2/dat.h
+++ b/sys/src/9/teg2/dat.h
@@ -21,6 +21,7 @@
typedef struct Conf Conf;
typedef struct Confmem Confmem;
+typedef struct FPalloc FPalloc;
typedef struct FPsave FPsave;
typedef struct PFPU PFPU;
typedef struct ISAConf ISAConf;
@@ -87,8 +88,14 @@
* each must be able to hold an Internal from fpi.h for sw emulation.
*/
ulong regs[Maxfpregs][3];
+};
- int fpstate;
+struct FPalloc
+{
+ FPsave;
+
+ /* the following fields are not visible to devproc */
+ int fpstate; /* FPinactive or FPemu */
uintptr pc; /* of failed fp instr. */
};
@@ -95,7 +102,8 @@
struct PFPU
{
int fpstate;
- FPsave fpsave[1];
+ FPalloc *fpsave;
+ FPalloc *ofpsave;
};
enum
@@ -102,11 +110,11 @@
{
FPinit,
FPactive,
- FPinactive,
+ FPinactive, /* fpsave valid when fpstate >= FPincative */
FPemu,
/* bit or'd with the state */
- FPillegal= 0x100,
+ FPnotify = 0x100,
};
struct Confmem
--- a/sys/src/9/teg2/fns.h
+++ b/sys/src/9/teg2/fns.h
@@ -144,7 +144,7 @@
extern int fpudevprocio(Proc*, void*, long, uintptr, int);
extern void fpuinit(void);
extern void fpunoted(void);
-extern void fpunotify(Ureg*);
+extern void fpunotify(void);
extern void fpuprocrestore(Proc*);
extern void fpuprocsave(Proc*);
extern void fpusysprocsetup(Proc*);
--- a/sys/src/9/teg2/softfpu.c
+++ b/sys/src/9/teg2/softfpu.c
@@ -20,7 +20,7 @@
}
void
-fpunotify(Ureg*)
+fpunotify(void)
{
/*
* Called when a note is about to be delivered to a
--- a/sys/src/9/teg2/syscall.c
+++ b/sys/src/9/teg2/syscall.c
@@ -45,7 +45,6 @@
fpunoted();
nf = up->ureg;
-
/* sanity clause */
if(!okaddr((uintptr)nf, sizeof(NFrame), 0)){
qunlock(&up->debug);
@@ -104,7 +103,6 @@
int
notify(Ureg* ureg)
{
- u32int s;
uintptr sp;
NFrame *nf;
char *msg;
@@ -114,9 +112,7 @@
if(up->nnote == 0)
return 0;
- fpunotify(ureg);
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -151,8 +147,9 @@
ureg->pc = (uintptr)up->notify;
ureg->r0 = (uintptr)nf->arg0;
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
l1cache->wb(); /* is this needed? */
return 1;
--- a/sys/src/9/xen/fns.h
+++ b/sys/src/9/xen/fns.h
@@ -15,6 +15,8 @@
void fpuprocfork(Proc*);
void fpuprocsave(Proc*);
void fpuprocrestore(Proc*);
+void fpunotify(Proc*);
+void fpunoted(Proc*);
int cpuidentify(void);
void cpuidprint(void);
void (*cycles)(uvlong*);
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -470,7 +470,7 @@
int
notify(Ureg* ureg)
{
- ulong s, sp;
+ ulong sp;
char *msg;
if(up->procctl)
@@ -478,13 +478,7 @@
if(up->nnote == 0)
return 0;
- if(up->fpstate == FPactive){
- fpsave(up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -515,8 +509,9 @@
*(ulong*)(sp+0*BY2WD) = 0; /* arg 0 is pc */
ureg->usp = sp;
ureg->pc = (ulong)up->notify;
+ splhi();
+ fpunotify(up);
qunlock(&up->debug);
- splx(s);
return 1;
}
@@ -537,9 +532,11 @@
}
up->notified = 0;
- nureg = up->ureg; /* pointer to user returned Ureg struct */
+ splhi();
+ fpunoted(up);
+ spllo();
- up->fpstate &= ~FPillegal;
+ nureg = up->ureg; /* pointer to user returned Ureg struct */
/* sanity clause */
oureg = (ulong)nureg;
--- a/sys/src/9/zynq/dat.h
+++ b/sys/src/9/zynq/dat.h
@@ -46,7 +46,8 @@
struct PFPU
{
int fpstate;
- FPsave fpsave[1];
+ FPsave *fpsave;
+ FPsave *ofpsave;
};
enum
@@ -54,7 +55,7 @@
FPinit,
FPactive,
FPinactive,
- FPillegal = 0x100
+ FPnotify = 0x100
};
struct Confmem
--- a/sys/src/9/zynq/main.c
+++ b/sys/src/9/zynq/main.c
@@ -43,30 +43,6 @@
}
}
-void
-procfork(Proc *p)
-{
- ulong s;
-
- s = splhi();
- switch(up->fpstate & ~FPillegal){
- case FPactive:
- fpsave(up->fpsave);
- up->fpstate = FPinactive;
- case FPinactive:
- memmove(p->fpsave, up->fpsave, sizeof(FPsave));
- p->fpstate = FPinactive;
- }
- splx(s);
-}
-
-void
-procsetup(Proc *p)
-{
- p->fpstate = FPinit;
- fpoff();
-}
-
ulong *l2;
void
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -116,27 +116,47 @@
up->insyscall = insyscall;
}
-static void
-mathtrap(Ureg *, ulong)
+static FPsave*
+fpalloc(void)
{
- int s;
+ FPsave *f;
- if((up->fpstate & FPillegal) != 0){
- postnote(up, 1, "sys: floating point in note handler", NDebug);
- return;
+ while((f = mallocalign(sizeof(FPsave), FPalign, 0, 0)) == nil){
+ int x = spllo();
+ resrcwait("no memory for FPsave");
+ splx(x);
}
+ return f;
+}
+
+static void
+fpfree(FPsave *f)
+{
+ free(f);
+}
+
+static void
+mathtrap(Ureg *, ulong)
+{
switch(up->fpstate){
+ case FPinit|FPnotify:
+ /* wet floor */
case FPinit:
- s = splhi();
+ if(up->fpsave == nil)
+ up->fpsave = fpalloc();
fpinit();
up->fpstate = FPactive;
- splx(s);
break;
+ case FPinactive|FPnotify:
+ spllo();
+ qlock(&up->debug);
+ notefpsave(up);
+ qunlock(&up->debug);
+ splhi();
+ /* wet floor */
case FPinactive:
- s = splhi();
fprestore(up->fpsave);
up->fpstate = FPactive;
- splx(s);
break;
case FPactive:
postnote(up, 1, "sys: floating point error", NDebug);
@@ -155,7 +175,6 @@
case PsrMund:
ureg->pc -= 4;
if(user){
- spllo();
if(okaddr(ureg->pc, 4, 0)){
opc = *(ulong*)ureg->pc;
if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){
@@ -277,10 +296,52 @@
kexit(ureg);
}
+static void
+fpunotify(void)
+{
+ if(up->fpstate == FPactive){
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPnotify;
+}
+
+static void
+fpunoted(void)
+{
+ if(up->fpstate & FPnotify){
+ up->fpstate &= ~FPnotify;
+ } else {
+ FPsave *o;
+
+ if(up->fpstate == FPactive)
+ fpclear();
+ if((o = up->ofpsave) != nil) {
+ up->ofpsave = nil;
+ fpfree(up->fpsave);
+ up->fpsave = o;
+ up->fpstate = FPinactive;
+ } else {
+ up->fpstate = FPinit;
+ }
+ }
+}
+
+FPsave*
+notefpsave(Proc *p)
+{
+ if(p->fpstate == (FPinactive|FPnotify)){
+ p->ofpsave = fpalloc();
+ memmove(p->ofpsave, p->fpsave, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->ofpsave;
+}
+
int
notify(Ureg *ureg)
{
- ulong s, sp;
+ ulong sp;
char *msg;
if(up->procctl)
@@ -288,13 +349,7 @@
if(up->nnote == 0)
return 0;
- if(up->fpstate == FPactive){
- fpsave(up->fpsave);
- up->fpstate = FPinactive;
- }
- up->fpstate |= FPillegal;
-
- s = spllo();
+ spllo();
qlock(&up->debug);
msg = popnote(ureg);
if(msg == nil){
@@ -328,8 +383,10 @@
ureg->sp = sp;
ureg->pc = (uintptr) up->notify;
ureg->r14 = 0;
+
+ splhi();
+ fpunotify();
qunlock(&up->debug);
- splx(s);
return 1;
}
@@ -346,10 +403,12 @@
pexit("Suicide", 0);
}
up->notified = 0;
-
- nureg = up->ureg;
- up->fpstate &= ~FPillegal;
-
+
+ splhi();
+ fpunoted();
+ spllo();
+
+ nureg = up->ureg;
oureg = (ulong) nureg;
if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
qunlock(&up->debug);
@@ -472,11 +531,20 @@
void
procsave(Proc *p)
{
- if(p->fpstate == FPactive){
- if(p->state == Moribund)
+ if(p->state == Moribund){
+ if(p->fpstate == FPactive)
fpclear();
- else
- fpsave(p->fpsave);
+ p->fpstate = FPinit;
+ if(p->fpsave != nil){
+ fpfree(p->fpsave);
+ p->fpsave = nil;
+ }
+ if(p->ofpsave != nil){
+ fpfree(p->ofpsave);
+ p->ofpsave = nil;
+ }
+ } else if(p->fpstate == FPactive){
+ fpsave(p->fpsave);
p->fpstate = FPinactive;
}
l1switch(&m->l1, 0);
@@ -485,6 +553,46 @@
void
procrestore(Proc*)
{
+}
+
+void
+procfork(Proc *p)
+{
+ int s;
+
+ s = splhi();
+ switch(up->fpstate & ~FPnotify){
+ case FPactive:
+ fpsave(up->fpsave);
+ up->fpstate = FPinactive;
+ /* wet floor */
+ case FPinactive:
+ if(p->fpsave == nil)
+ p->fpsave = fpalloc();
+ memmove(p->fpsave, up->fpsave, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ splx(s);
+}
+
+void
+procsetup(Proc *p)
+{
+ int s;
+
+ s = splhi();
+ p->fpstate = FPinit;
+ fpoff();
+ splx(s);
+
+ if(p->fpsave != nil){
+ fpfree(p->fpsave);
+ p->fpsave = nil;
+ }
+ if(p->ofpsave != nil){
+ fpfree(p->ofpsave);
+ p->ofpsave = nil;
+ }
}
void
--
⑨