shithub: front

Download patch

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);
 }
 
 /*
--