Port-hppa archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Patch: hppa lazy FPU switching and QEMU bugs



On Tue, Aug 04, 2026 at 08:28:45PM -0400, Thor Lancelot Simon wrote:
> On Tue, Aug 04, 2026 at 01:03:51PM +0000, Taylor R Campbell wrote:
> > > Date: Mon, 3 Aug 2026 22:57:54 -0400
> > > From: Thor Lancelot Simon <tls%panix.com@localhost>
> > > References: <anDzFs-VkFP_opy2%panix.com@localhost>
> > > 
> > > On Mon, Aug 03, 2026 at 03:59:18PM -0400, Thor Lancelot Simon wrote:
> > > > 
> > > > This host manages QEMU guests running the exact same version of NetBSD
> > > > on 14 other emulated architectures.  Only hppa blows up like this.  I
> > > > suppose some day someone will figure out why.
> > > 
> > > Actually the problem is not ML-KEM at all nor OpenSSL.  It's a bug in QEMU,
> > > an information leak that can swap processes' FP registers!
> > 
> > Yes, and we already have an open PR about this:
> > 
> > PR port-hppa/59114: hppa: eager fpu switching for qemu and/or spectre
> > mitigation
> > https://gnats.NetBSD.org/59114
> 
> Well, I've got a fix - coded, unfortunately, by Claude, and it's moderately
> intrusive so I will have to take a little time to re-code it per our AI
> prohibition.

I rewrote it, and managed to make it a little shorter and simpler.
The result is below.  It would be good to know it works on
actual hardware.

Index: sys/arch/hppa/conf/files.hppa
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/conf/files.hppa,v
retrieving revision 1.29
diff -u -r1.29 files.hppa
--- sys/arch/hppa/conf/files.hppa	20 Oct 2025 09:42:46 -0000	1.29
+++ sys/arch/hppa/conf/files.hppa	17 Aug 2026 04:58:12 -0000
@@ -111,6 +111,7 @@
 device	fpu
 attach	fpu at gedoens
 file	arch/hppa/dev/fpu.c		fpu
+defflag opt_hppa_fpu.h HPPA_FPU_EAGER
 
 # Phantom PseudoBC GSC+ Port
 device	phantomas: gedoens
Index: sys/arch/hppa/hppa/fpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/hppa/fpu.c,v
retrieving revision 1.27
diff -u -r1.27 fpu.c
--- sys/arch/hppa/hppa/fpu.c	16 Apr 2020 05:44:43 -0000	1.27
+++ sys/arch/hppa/hppa/fpu.c	17 Aug 2026 04:58:12 -0000
@@ -36,6 +36,10 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.27 2020/04/16 05:44:43 skrll Exp $");
 
+#ifdef _KERNEL_OPT
+#include "opt_hppa_fpu.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
@@ -78,10 +82,15 @@
 /* The number of times we have had to switch the FPU context. */
 u_int fpu_csw;
 
+/* Don't use the default lazy FPU switching */
+int fpu_eager;
+
 /* In locore.S, this swaps states in and out of the FPU. */
 void hppa_fpu_swapout(struct pcb *);
 void hppa_fpu_swap(struct fpreg *, struct fpreg *);
 
+void hppa_fpu_switch(struct lwp *);
+
 static int hppa_fpu_ls(struct trapframe *, struct lwp *);
 
 /*
@@ -139,14 +148,16 @@
 void
 hppa_fpu_bootstrap(u_int ccr_enable)
 {
-	uint32_t junk[2];
-	uint32_t vers[2];
+	uint32_t junk[2] __aligned(8);
+	uint32_t vers[2] __aligned(8);
+	u_int ccr;
 
 	/* See if we have a present and functioning hardware FPU. */
 	fpu_present = (ccr_enable & HPPA_FPUS) == HPPA_FPUS;
 	if (!fpu_present) {
 		fpu_csw = 0;
 		curcpu()->ci_fpu_state = 0;
+		curcpu()->ci_fpu_lwp = NULL;
 
 		return;
 	}
@@ -182,9 +193,32 @@
 	 */
 	fpu_csw = 0;
 	curcpu()->ci_fpu_state = 0;
+	curcpu()->ci_fpu_lwp = NULL;
 	mtctl(ccr_enable & (CCR_MASK ^ HPPA_FPUS), CR_CCR);
 
 	fpu_version = vers[0];
+
+#ifdef HPPA_FPU_EAGER
+	fpu_eager = 1;
+	aprint_normal("fpu: eager switching\n");
+#else
+	/*
+	 * Handle QEMU, which does not check whether the FPU
+	 * is disabled before trying to run instructions on it,
+	 * thus never traps, thus never triggers our lazy FPU
+	 * switching scheme.
+	 */
+	mtctl(0, CR_CCR);
+	__asm volatile("fstds %%fr0, 0(%0)" :: "r" (junk) : "memory");
+	mfctl(CR_CCR, ccr);
+	if (!(ccr & HPPA_FPUS)) {
+		fpu_eager = 1;
+		/* No trap, so no trap handler, so re-enable FPU ourselves. */
+		mtctl(HPPA_FPUS, CR_CCR);
+		aprint_normal("fpu: emulation trap failure; "
+		    "using eager switching\n");
+	}
+#endif
 }
 
 /*
@@ -212,6 +246,14 @@
 
 	hppa_fpu_swapout(pcb);
 	ci->ci_fpu_state = 0;
+	/*
+	 * If we are doing eager FPU switching, hang onto the
+	 * LWP - if it uses the FPU again, the regs will need to be
+	 * saved again.
+	 */
+	if (!fpu_eager) {
+		ci->ci_fpu_lwp = NULL;
+	}
 }
 
 /*
@@ -424,3 +466,28 @@
 		trapsignal(l, &ksi);
 	}
 }
+/*
+ * Immediately switch current LWP's FP regs for those of the new LWP's;
+ * called from cpu_switchto if hppa_fpu_switch is set (if we are avoiding
+ * lazy FPU switching).
+ */
+void
+hppa_fpu_switch(struct lwp *newl)
+{
+    struct cpu_info *ci = curcpu();
+    struct pcb *oldpcb, *newpcb;
+    struct fpreg *oldregs = NULL, *newregs;
+
+    if (!fpu_present) return;
+    if (ci->ci_fpu_lwp == newl) return;
+
+    if (ci->ci_fpu_lwp != NULL) {
+	oldpcb = lwp_getpcb(ci->ci_fpu_lwp);
+	oldregs = oldpcb->pcb_fpregs;
+    }
+
+    newpcb = lwp_getpcb(newl);
+    newregs = newpcb->pcb_fpregs;
+
+    hppa_fpu_swap(oldregs, newregs);
+}
Index: sys/arch/hppa/hppa/locore.S
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/hppa/locore.S,v
retrieving revision 1.7
diff -u -r1.7 locore.S
--- sys/arch/hppa/hppa/locore.S	3 Apr 2025 17:49:49 -0000	1.7
+++ sys/arch/hppa/hppa/locore.S	17 Aug 2026 04:58:12 -0000
@@ -945,13 +945,35 @@
 noras:
 
 	/*
-	 * We do have a hardware FPU.  If the LWP
+	 * We do have a hardware FPU.  Two paths: eager
+	 * (if selected by kernel config, or if emulation trap broken),
+	 * or lazy.
+	 */
+	.import fpu_eager, data
+	ldil	L%fpu_eager, %t1
+	ldw	R%fpu_eager(%t1), %t1
+	comib,=,n 0, %t1, L$fpu_lazy
+
+	/*
+	 * Eager path - via C helper
+	 */
+	stw	%arg0, HPPA_FRAME_ARG(0)(%r3)
+	stw	%arg1, HPPA_FRAME_ARG(1)(%r3)
+	copy	%arg1, %arg0
+	CALL(hppa_fpu_switch, %r1)
+	ldw	HPPA_FRAME_ARG(1)(%r3), %arg1
+	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0
+	b,n	switch_return
+
+	/*
+	 * Lazy path.  If the LWP
 	 * that we just switched to has its state in the
 	 * FPU, enable the FPU, else disable it, so if
 	 * the LWP does try to use the coprocessor
 	 * we'll get an assist emulation trap to swap
 	 * states.
 	 */
+L$fpu_lazy:
 	GET_CURCPU(%t1)
 	mfctl	CR_CCR, %r1
 	mfctl	CR_FPPADDR, %t2
Index: sys/arch/hppa/include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/include/cpu.h,v
retrieving revision 1.13
diff -u -r1.13 cpu.h
--- sys/arch/hppa/include/cpu.h	23 Feb 2023 14:55:36 -0000	1.13
+++ sys/arch/hppa/include/cpu.h	17 Aug 2026 04:58:12 -0000
@@ -290,6 +290,8 @@
 	hppa_hpa_t	ci_hpa;
 	register_t	ci_psw;		/* Processor Status Word. */
 	paddr_t		ci_fpu_state;	/* LWP FPU state address, or zero. */
+	struct lwp	*ci_fpu_lwp;	/* If eager mode, LWP vaddr or NULL */
+
 	u_long		ci_itmr;
 
 	int		ci_cpuid;	/* CPU index (see cpus[] array) */


Home | Main Index | Thread Index | Old Index