ref: 568663c4e0e498f78129d18280e85c90a1d0a4d4
parent: 4091eb6fcd02ae5162423788f7da23544a28a3a6
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 13 16:06:13 EDT 2025
kernel: restore kernel fpu state on fault*() error Theres one special case when handling a page-fault from syscall handler which accesses user-memory and we are unable to handle the fault. In that case, faultamd64()/faultarm64() gotolabel() to the last waserror() handler, skipping the return back to trap(), which would have restored the kernel-fpu context. As we now track the nested FPsave context using FPalloc.link pointers, we can avoid returning FPalloc* from fpukenter() and passing the argument to fpukexit().
--- a/sys/src/9/arm64/fns.h
+++ b/sys/src/9/arm64/fns.h
@@ -93,8 +93,8 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPalloc* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPalloc*);
+extern void fpukenter(Ureg*);
+extern void fpukexit(Ureg*);
extern void fpunotify(Proc*);
extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
--- a/sys/src/9/arm64/fpu.c
+++ b/sys/src/9/arm64/fpu.c
@@ -75,7 +75,7 @@
* are handled between fpukenter() and fpukexit(),
* so they can use floating point and vector instructions.
*/
-FPalloc*
+void
fpukenter(Ureg*)
{
if(up == nil){
@@ -85,9 +85,8 @@
/* wet floor */
case FPinactive:
m->fpstate = FPinit;
- return m->fpsave;
}
- return nil;
+ return;
}
switch(up->fpstate){
@@ -96,7 +95,7 @@
fpoff();
/* wet floor */
case FPprotected:
- return nil;
+ return;
}
switch(up->kfpstate){
@@ -105,14 +104,14 @@
/* wet floor */
case FPinactive:
up->kfpstate = FPinit;
- return up->kfpsave;
}
- return nil;
}
void
-fpukexit(Ureg *ureg, FPalloc *o)
+fpukexit(Ureg *ureg)
{
+ FPalloc *a;
+
if(up == nil){
switch(m->fpstate){
case FPactive:
@@ -119,12 +118,11 @@
fpoff();
/* wet floor */
case FPinactive:
- fpfree(m->fpsave);
- m->fpstate = FPinit;
+ a = m->fpsave;
+ m->fpsave = a->link;
+ fpfree(a);
}
- m->fpsave = o;
- if(o != nil)
- m->fpstate = FPinactive;
+ m->fpstate = m->fpsave != nil? FPinactive: FPinit;
return;
}
@@ -141,12 +139,11 @@
fpoff();
/* wet floor */
case FPinactive:
- fpfree(up->kfpsave);
- up->kfpstate = FPinit;
+ a = up->kfpsave;
+ up->kfpsave = a->link;
+ fpfree(a);
}
- up->kfpsave = o;
- if(o != nil)
- up->kfpstate = FPinactive;
+ up->kfpstate = up->kfpsave != nil? FPinactive: FPinit;
}
void
--- a/sys/src/9/arm64/main.c
+++ b/sys/src/9/arm64/main.c
@@ -49,7 +49,7 @@
sp[0] = (void*)&sp[1];
splhi();
- fpukexit(nil, nil);
+ fpukexit(nil);
touser((uintptr)sp);
}
--- a/sys/src/9/arm64/trap.c
+++ b/sys/src/9/arm64/trap.c
@@ -97,7 +97,6 @@
void
trap(Ureg *ureg)
{
- FPalloc *f = nil;
u32int type, intr;
int user;
@@ -114,7 +113,7 @@
case 0x21: // instruction abort from same level
case 0x24: // data abort from lower level
case 0x25: // data abort from same level
- f = fpukenter(ureg);
+ fpukenter(ureg);
faultarm64(ureg);
break;
case 0x07: // SIMD/FP
@@ -123,13 +122,13 @@
break;
case 0x00: // unknown
if(intr == 1){
- f = fpukenter(ureg);
+ fpukenter(ureg);
preempted(irq(ureg));
break;
}
if(intr == 3){
case 0x2F: // SError interrupt
- f = fpukenter(ureg);
+ fpukenter(ureg);
if(buserror != nil && (*buserror)(ureg))
break;
dumpregs(ureg);
@@ -165,7 +164,7 @@
case 0x3A: // vector catch exception (A32 only)
case 0x3C: // BRK instruction (A64 only)
default:
- f = fpukenter(ureg);
+ fpukenter(ureg);
if(!userureg(ureg)){
dumpregs(ureg);
panic("unhandled trap");
@@ -182,7 +181,7 @@
kexit(ureg);
}
if(type != 0x07 && type != 0x2C)
- fpukexit(ureg, f);
+ fpukexit(ureg);
}
void
@@ -275,7 +274,7 @@
sched();
kexit(ureg);
- fpukexit(ureg, nil);
+ fpukexit(ureg);
}
int
@@ -436,6 +435,10 @@
pprint("suicide: sys: %s\n", up->errstr);
pexit(up->errstr, 1);
}
+ /* skipping bottom of trap(), so do it outselfs */
+ splhi();
+ fpukexit(ureg);
+ spllo();
nexterror();
}
}
--- a/sys/src/9/bcm64/fns.h
+++ b/sys/src/9/bcm64/fns.h
@@ -92,8 +92,8 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPalloc* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPalloc*);
+extern void fpukenter(Ureg*);
+extern void fpukexit(Ureg*);
extern void fpunotify(Proc*);
extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
--- a/sys/src/9/bcm64/main.c
+++ b/sys/src/9/bcm64/main.c
@@ -47,7 +47,7 @@
sp[0] = (void*)&sp[1];
splhi();
- fpukexit(nil, nil);
+ fpukexit(nil);
touser((uintptr)sp);
}
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -95,8 +95,8 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPalloc* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPalloc*);
+extern void fpukenter(Ureg*);
+extern void fpukexit(Ureg*);
extern void fpunotify(Proc*);
extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
--- a/sys/src/9/imx8/main.c
+++ b/sys/src/9/imx8/main.c
@@ -163,7 +163,7 @@
sp[0] = (void*)&sp[1];
splhi();
- fpukexit(nil, nil);
+ fpukexit(nil);
touser((uintptr)sp);
}
--- a/sys/src/9/lx2k/fns.h
+++ b/sys/src/9/lx2k/fns.h
@@ -95,8 +95,8 @@
extern void fpuprocfork(Proc*);
extern void fpuprocsave(Proc*);
extern void fpuprocrestore(Proc*);
-extern FPalloc* fpukenter(Ureg*);
-extern void fpukexit(Ureg*, FPalloc*);
+extern void fpukenter(Ureg*);
+extern void fpukexit(Ureg*);
extern void fpunotify(Proc*);
extern void fpunoted(Proc*);
extern void mathtrap(Ureg*);
--- a/sys/src/9/lx2k/main.c
+++ b/sys/src/9/lx2k/main.c
@@ -163,7 +163,7 @@
sp[0] = (void*)&sp[1];
splhi();
- fpukexit(nil, nil);
+ fpukexit(nil);
touser((uintptr)sp);
}
--- a/sys/src/9/pc/devvmx.c
+++ b/sys/src/9/pc/devvmx.c
@@ -1113,7 +1113,7 @@
s = splhi();
#ifdef KFPSTATE
- fpukexit(nil, nil);
+ fpukexit(nil);
#endif
fpinit();
fpsave(&vmx->fp);
@@ -1832,7 +1832,7 @@
if((vmx->dr[7] & ~0xd400) != 0)
putdr01236(vmx->dr);
#ifdef KFPSTATE
- fpukexit(nil, nil);
+ fpukexit(nil);
#endif
fprestore(&vmx->fp);
if(vmx->xcr0 != m->xcr0)
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -35,8 +35,8 @@
void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
void fpinit(void);
-FPalloc*fpukenter(Ureg*);
-void fpukexit(Ureg*, FPalloc*);
+void fpukenter(Ureg*);
+void fpukexit(Ureg*);
void fpuprocfork(Proc*);
void fpuprocrestore(Proc*);
void fpuprocsave(Proc*);
--- a/sys/src/9/pc64/fpu.c
+++ b/sys/src/9/pc64/fpu.c
@@ -358,7 +358,7 @@
* are handled between fpukenter() and fpukexit(),
* so they can use floating point and vector instructions.
*/
-FPalloc*
+void
fpukenter(Ureg *)
{
if(up == nil){
@@ -368,9 +368,8 @@
/* wet floor */
case FPinactive:
m->fpstate = FPinit;
- return m->fpsave;
}
- return nil;
+ return;
}
switch(up->fpstate){
@@ -379,7 +378,7 @@
_stts();
/* wet floor */
case FPprotected:
- return nil;
+ return;
}
switch(up->kfpstate){
@@ -388,14 +387,14 @@
/* wet floor */
case FPinactive:
up->kfpstate = FPinit;
- return up->kfpsave;
}
- return nil;
}
void
-fpukexit(Ureg *ureg, FPalloc *o)
+fpukexit(Ureg *ureg)
{
+ FPalloc *a;
+
if(up == nil){
switch(m->fpstate){
case FPactive:
@@ -403,12 +402,11 @@
_stts();
/* wet floor */
case FPinactive:
- fpfree(m->fpsave);
- m->fpstate = FPinit;
+ a = m->fpsave;
+ m->fpsave = a->link;
+ fpfree(a);
}
- m->fpsave = o;
- if(o != nil)
- m->fpstate = FPinactive;
+ m->fpstate = m->fpsave != nil? FPinactive: FPinit;
return;
}
@@ -426,12 +424,11 @@
_stts();
/* wet floor */
case FPinactive:
- fpfree(up->kfpsave);
- up->kfpstate = FPinit;
+ a = up->kfpsave;
+ up->kfpsave = a->link;
+ fpfree(a);
}
- up->kfpsave = o;
- if(o != nil)
- up->kfpstate = FPinactive;
+ up->kfpstate = up->kfpsave != nil? FPinactive: FPinit;
}
void
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -170,7 +170,7 @@
sp[0] = nil;
splhi();
- fpukexit(nil, nil);
+ fpukexit(nil);
touser(sp);
}
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -133,12 +133,11 @@
trap(Ureg *ureg)
{
int vno, user;
- FPalloc *f = nil;
vno = ureg->type;
user = kenter(ureg);
if(vno != VectorCNA)
- f = fpukenter(ureg);
+ fpukenter(ureg);
if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
if(!user){
@@ -184,7 +183,7 @@
kexit(ureg);
}
if(vno != VectorCNA)
- fpukexit(ureg, f);
+ fpukexit(ureg);
}
void
@@ -410,6 +409,10 @@
pprint("suicide: sys: %s\n", up->errstr);
pexit(up->errstr, 1);
}
+ /* skipping bottom of trap(), so do it outselfs */
+ splhi();
+ fpukexit(ureg);
+ spllo();
nexterror();
}
}
@@ -537,7 +540,7 @@
sched();
kexit(ureg);
- fpukexit(ureg, nil);
+ fpukexit(ureg);
}
/*
--
⑨