Module Name: src Committed By: martin Date: Sat Jun 23 11:39:02 UTC 2018
Modified Files: src/sys/arch/amd64/amd64 [netbsd-8]: locore.S src/sys/arch/i386/i386 [netbsd-8]: locore.S src/sys/arch/x86/include [netbsd-8]: cpu.h fpu.h src/sys/arch/x86/x86 [netbsd-8]: fpu.c identcpu.c vm_machdep.c x86_machdep.c Log Message: Pull up the following, via patch, requested by maxv in ticket #897: sys/arch/amd64/amd64/locore.S 1.166 (patch) sys/arch/i386/i386/locore.S 1.157 (patch) sys/arch/x86/include/cpu.h 1.92 (patch) sys/arch/x86/include/fpu.h 1.9 (patch) sys/arch/x86/x86/fpu.c 1.33-1.39 (patch) sys/arch/x86/x86/identcpu.c 1.72 (patch) sys/arch/x86/x86/vm_machdep.c 1.34 (patch) sys/arch/x86/x86/x86_machdep.c 1.116,1.117 (patch) Support eager fpu switch, to work around INTEL-SA-00145. Provide a sysctl machdep.fpu_eager, which gets automatically initialized to 1 on affected CPUs. To generate a diff of this commit: cvs rdiff -u -r1.123.6.6 -r1.123.6.7 src/sys/arch/amd64/amd64/locore.S cvs rdiff -u -r1.145.6.3 -r1.145.6.4 src/sys/arch/i386/i386/locore.S cvs rdiff -u -r1.71.2.6 -r1.71.2.7 src/sys/arch/x86/include/cpu.h cvs rdiff -u -r1.6 -r1.6.28.1 src/sys/arch/x86/include/fpu.h cvs rdiff -u -r1.12.8.1 -r1.12.8.2 src/sys/arch/x86/x86/fpu.c cvs rdiff -u -r1.55.2.3 -r1.55.2.4 src/sys/arch/x86/x86/identcpu.c cvs rdiff -u -r1.28.6.3 -r1.28.6.4 src/sys/arch/x86/x86/vm_machdep.c cvs rdiff -u -r1.91.4.3 -r1.91.4.4 src/sys/arch/x86/x86/x86_machdep.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/amd64/amd64/locore.S diff -u src/sys/arch/amd64/amd64/locore.S:1.123.6.6 src/sys/arch/amd64/amd64/locore.S:1.123.6.7 --- src/sys/arch/amd64/amd64/locore.S:1.123.6.6 Sat May 5 15:00:29 2018 +++ src/sys/arch/amd64/amd64/locore.S Sat Jun 23 11:39:01 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.123.6.6 2018/05/05 15:00:29 martin Exp $ */ +/* $NetBSD: locore.S,v 1.123.6.7 2018/06/23 11:39:01 martin Exp $ */ /* * Copyright-o-rama! @@ -1094,6 +1094,20 @@ skip_save: popq %rdx #endif +#ifndef XEN + /* RDI/RSI got clobbered. */ + movq %r13,%rdi + movq %r12,%rsi + + pushq %rdx + movb _C_LABEL(x86_fpu_eager),%dl + testb %dl,%dl + jz .Lno_eagerfpu + callq _C_LABEL(fpu_eagerswitch) +.Lno_eagerfpu: + popq %rdx +#endif + /* Switch to newlwp's stack. */ movq L_PCB(%r12),%r14 movq PCB_RSP(%r14),%rsp Index: src/sys/arch/i386/i386/locore.S diff -u src/sys/arch/i386/i386/locore.S:1.145.6.3 src/sys/arch/i386/i386/locore.S:1.145.6.4 --- src/sys/arch/i386/i386/locore.S:1.145.6.3 Tue Mar 13 15:47:44 2018 +++ src/sys/arch/i386/i386/locore.S Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: locore.S,v 1.145.6.3 2018/03/13 15:47:44 martin Exp $ */ +/* $NetBSD: locore.S,v 1.145.6.4 2018/06/23 11:39:02 martin Exp $ */ /* * Copyright-o-rama! @@ -128,7 +128,7 @@ */ #include <machine/asm.h> -__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.145.6.3 2018/03/13 15:47:44 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.145.6.4 2018/06/23 11:39:02 martin Exp $"); #include "opt_compat_oldboot.h" #include "opt_copy_symtab.h" @@ -1089,6 +1089,19 @@ ENTRY(cpu_switchto) movl %ebp,PCB_EBP(%eax) skip_save: +#ifndef XEN + pushl %edx + movb _C_LABEL(x86_fpu_eager),%dl + testb %dl,%dl + jz .Lno_eagerfpu + pushl %edi + pushl %esi + call _C_LABEL(fpu_eagerswitch) + addl $8,%esp +.Lno_eagerfpu: + popl %edx +#endif + /* Switch to newlwp's stack. */ movl L_PCB(%edi),%ebx movl PCB_EBP(%ebx),%ebp Index: src/sys/arch/x86/include/cpu.h diff -u src/sys/arch/x86/include/cpu.h:1.71.2.6 src/sys/arch/x86/include/cpu.h:1.71.2.7 --- src/sys/arch/x86/include/cpu.h:1.71.2.6 Sat Jun 9 15:12:21 2018 +++ src/sys/arch/x86/include/cpu.h Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.71.2.6 2018/06/09 15:12:21 martin Exp $ */ +/* $NetBSD: cpu.h,v 1.71.2.7 2018/06/23 11:39:02 martin Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -424,6 +424,7 @@ extern int x86_fpu_save; #define FPU_SAVE_XSAVEOPT 3 extern unsigned int x86_fpu_save_size; extern uint64_t x86_xsave_features; +extern bool x86_fpu_eager; extern void (*x86_cpu_idle)(void); #define cpu_idle() (*x86_cpu_idle)() Index: src/sys/arch/x86/include/fpu.h diff -u src/sys/arch/x86/include/fpu.h:1.6 src/sys/arch/x86/include/fpu.h:1.6.28.1 --- src/sys/arch/x86/include/fpu.h:1.6 Tue Feb 25 22:16:52 2014 +++ src/sys/arch/x86/include/fpu.h Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu.h,v 1.6 2014/02/25 22:16:52 dsl Exp $ */ +/* $NetBSD: fpu.h,v 1.6.28.1 2018/06/23 11:39:02 martin Exp $ */ #ifndef _X86_FPU_H_ #define _X86_FPU_H_ @@ -15,6 +15,8 @@ void fpuinit(struct cpu_info *); void fpusave_lwp(struct lwp *, bool); void fpusave_cpu(bool); +void fpu_eagerswitch(struct lwp *, struct lwp *); + void fpu_set_default_cw(struct lwp *, unsigned int); void fputrap(struct trapframe *); Index: src/sys/arch/x86/x86/fpu.c diff -u src/sys/arch/x86/x86/fpu.c:1.12.8.1 src/sys/arch/x86/x86/fpu.c:1.12.8.2 --- src/sys/arch/x86/x86/fpu.c:1.12.8.1 Thu Dec 21 19:33:15 2017 +++ src/sys/arch/x86/x86/fpu.c Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu.c,v 1.12.8.1 2017/12/21 19:33:15 snj Exp $ */ +/* $NetBSD: fpu.c,v 1.12.8.2 2018/06/23 11:39:02 martin Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. All @@ -96,7 +96,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12.8.1 2017/12/21 19:33:15 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12.8.2 2018/06/23 11:39:02 martin Exp $"); #include "opt_multiprocessor.h" @@ -107,6 +107,8 @@ __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12 #include <sys/file.h> #include <sys/proc.h> #include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/xcall.h> #include <machine/cpu.h> #include <machine/intr.h> @@ -125,6 +127,8 @@ __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12 #define stts() HYPERVISOR_fpu_taskswitch(1) #endif +bool x86_fpu_eager __read_mostly = false; + static inline union savefpu * process_fpframe(struct lwp *lwp) { @@ -228,6 +232,89 @@ fpuinit(struct cpu_info *ci) } static void +fpu_clear_amd(void) +{ + /* + * AMD FPUs do not restore FIP, FDP, and FOP on fxrstor and xrstor + * when FSW.ES=0, leaking other threads' execution history. + * + * Clear them manually by loading a zero (fldummy). We do this + * unconditionally, regardless of FSW.ES. + * + * Before that, clear the ES bit in the x87 status word if it is + * currently set, in order to avoid causing a fault in the + * upcoming load. + * + * Newer generations of AMD CPUs have CPUID_Fn80000008_EBX[2], + * which indicates that FIP/FDP/FOP are restored (same behavior + * as Intel). We're not using it though. + */ + if (fngetsw() & 0x80) + fnclex(); + fldummy(); +} + +static void +fpu_save(struct lwp *l) +{ + struct pcb *pcb = lwp_getpcb(l); + + if (i386_use_fxsave) { + if (x86_xsave_features != 0) + xsave(&pcb->pcb_savefpu, x86_xsave_features); + else + fxsave(&pcb->pcb_savefpu); + } else { + fnsave(&pcb->pcb_savefpu); + } +} + +static void +fpu_restore(struct lwp *l) +{ + struct pcb *pcb = lwp_getpcb(l); + + if (i386_use_fxsave) { + if (x86_xsave_features != 0) { + xrstor(&pcb->pcb_savefpu, x86_xsave_features); + } else { + fpu_clear_amd(); + fxrstor(&pcb->pcb_savefpu); + } + } else { + frstor(&pcb->pcb_savefpu); + } +} + +static void +fpu_eagerrestore(struct lwp *l) +{ + struct pcb *pcb = lwp_getpcb(l); + struct cpu_info *ci = curcpu(); + + clts(); + KASSERT(ci->ci_fpcurlwp == NULL); + KASSERT(pcb->pcb_fpcpu == NULL); + ci->ci_fpcurlwp = l; + pcb->pcb_fpcpu = ci; + fpu_restore(l); +} + +void +fpu_eagerswitch(struct lwp *oldlwp, struct lwp *newlwp) +{ + int s; + + s = splhigh(); + fpusave_cpu(true); + if (!(newlwp->l_flag & LW_SYSTEM)) + fpu_eagerrestore(newlwp); + splx(s); +} + +/* -------------------------------------------------------------------------- */ + +static void send_sigill(void *rip) { /* No fpu (486SX) - send SIGILL */ @@ -358,6 +445,11 @@ fpudna(struct trapframe *frame) pcb = lwp_getpcb(l); fl = ci->ci_fpcurlwp; if (fl != NULL) { + if (__predict_false(x86_fpu_eager)) { + panic("%s: FPU busy with EagerFPU enabled", + __func__); + } + /* * It seems we can get here on Xen even if we didn't * switch lwp. In this case do nothing @@ -373,6 +465,11 @@ fpudna(struct trapframe *frame) /* Save our state if on a remote CPU. */ if (pcb->pcb_fpcpu != NULL) { + if (__predict_false(x86_fpu_eager)) { + panic("%s: LWP busy with EagerFPU enabled", + __func__); + } + /* Explicitly disable preemption before dropping spl. */ kpreempt_disable(); splx(s); @@ -394,28 +491,7 @@ fpudna(struct trapframe *frame) ci->ci_fpcurlwp = l; pcb->pcb_fpcpu = ci; - if (i386_use_fxsave) { - if (x86_xsave_features != 0) { - xrstor(&pcb->pcb_savefpu, x86_xsave_features); - } else { - /* - * AMD FPU's do not restore FIP, FDP, and FOP on - * fxrstor, leaking other process's execution history. - * Clear them manually by loading a zero. - * - * Clear the ES bit in the x87 status word if it is - * currently set, in order to avoid causing a fault - * in the upcoming load. - */ - if (fngetsw() & 0x80) - fnclex(); - fldummy(); - - fxrstor(&pcb->pcb_savefpu); - } - } else { - frstor(&pcb->pcb_savefpu); - } + fpu_restore(l); KASSERT(ci == curcpu()); splx(s); @@ -442,14 +518,7 @@ fpusave_cpu(bool save) if (save) { clts(); - if (i386_use_fxsave) { - if (x86_xsave_features != 0) - xsave(&pcb->pcb_savefpu, x86_xsave_features); - else - fxsave(&pcb->pcb_savefpu); - } else { - fnsave(&pcb->pcb_savefpu); - } + fpu_save(l); } stts(); @@ -516,17 +585,28 @@ fpu_set_default_cw(struct lwp *l, unsign fpu_save->sv_os.fxo_dflt_cw = x87_cw; } -/* - * Exec needs to clear the fpu save area to avoid leaking info from the - * old process to userspace. - */ void fpu_save_area_clear(struct lwp *l, unsigned int x87_cw) { union savefpu *fpu_save; + struct pcb *pcb __diagused; + int s; - fpusave_lwp(l, false); + KASSERT(l == curlwp); + KASSERT((l->l_flag & LW_SYSTEM) == 0); fpu_save = process_fpframe(l); + pcb = lwp_getpcb(l); + + s = splhigh(); + if (x86_fpu_eager) { + KASSERT(pcb->pcb_fpcpu == NULL || + pcb->pcb_fpcpu == curcpu()); + fpusave_cpu(false); + } else { + splx(s); + fpusave_lwp(l, false); + } + KASSERT(pcb->pcb_fpcpu == NULL); if (i386_use_fxsave) { memset(&fpu_save->sv_xmm, 0, sizeof(fpu_save->sv_xmm)); @@ -539,6 +619,11 @@ fpu_save_area_clear(struct lwp *l, unsig fpu_save->sv_87.s87_cw = x87_cw; } fpu_save->sv_os.fxo_dflt_cw = x87_cw; + + if (x86_fpu_eager) { + fpu_eagerrestore(l); + splx(s); + } } /* For signal handlers the register values don't matter */ @@ -572,6 +657,8 @@ fpu_save_area_fork(struct pcb *pcb2, con if (extra > 0) memcpy(pcb2 + 1, pcb1 + 1, extra); + + KASSERT(pcb2->pcb_fpcpu == NULL); } @@ -651,3 +738,110 @@ process_read_fpregs_s87(struct lwp *l, s memcpy(fpregs, &fpu_save->sv_87, sizeof(fpu_save->sv_87)); } } + +/* -------------------------------------------------------------------------- */ + +static volatile unsigned long eagerfpu_cpu_barrier1 __cacheline_aligned; +static volatile unsigned long eagerfpu_cpu_barrier2 __cacheline_aligned; + +static void +eager_change_cpu(void *arg1, void *arg2) +{ + struct cpu_info *ci = curcpu(); + bool enabled = (bool)arg1; + int s; + + s = splhigh(); + + /* Rendez-vous 1. */ + atomic_dec_ulong(&eagerfpu_cpu_barrier1); + while (atomic_cas_ulong(&eagerfpu_cpu_barrier1, 0, 0) != 0) { + x86_pause(); + } + + fpusave_cpu(true); + if (ci == &cpu_info_primary) { + x86_fpu_eager = enabled; + } + + /* Rendez-vous 2. */ + atomic_dec_ulong(&eagerfpu_cpu_barrier2); + while (atomic_cas_ulong(&eagerfpu_cpu_barrier2, 0, 0) != 0) { + x86_pause(); + } + + splx(s); +} + +static int +eager_change(bool enabled) +{ + struct cpu_info *ci = NULL; + CPU_INFO_ITERATOR cii; + uint64_t xc; + + mutex_enter(&cpu_lock); + + /* + * We expect all the CPUs to be online. + */ + for (CPU_INFO_FOREACH(cii, ci)) { + struct schedstate_percpu *spc = &ci->ci_schedstate; + if (spc->spc_flags & SPCF_OFFLINE) { + printf("[!] cpu%d offline, EagerFPU not changed\n", + cpu_index(ci)); + mutex_exit(&cpu_lock); + return EOPNOTSUPP; + } + } + + /* Initialize the barriers */ + eagerfpu_cpu_barrier1 = ncpu; + eagerfpu_cpu_barrier2 = ncpu; + + printf("[+] %s EagerFPU...", + enabled ? "Enabling" : "Disabling"); + xc = xc_broadcast(0, eager_change_cpu, + (void *)enabled, NULL); + xc_wait(xc); + printf(" done!\n"); + + mutex_exit(&cpu_lock); + + return 0; +} + +static int +sysctl_machdep_fpu_eager(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + int error; + bool val; + + val = *(bool *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error != 0 || newp == NULL) + return error; + + if (val == x86_fpu_eager) + return 0; + return eager_change(val); +} + +void sysctl_eagerfpu_init(struct sysctllog **); + +void +sysctl_eagerfpu_init(struct sysctllog **clog) +{ + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_READWRITE, + CTLTYPE_BOOL, "fpu_eager", + SYSCTL_DESCR("Whether the kernel uses Eager FPU Switch"), + sysctl_machdep_fpu_eager, 0, + &x86_fpu_eager, 0, + CTL_MACHDEP, CTL_CREATE, CTL_EOL); +} Index: src/sys/arch/x86/x86/identcpu.c diff -u src/sys/arch/x86/x86/identcpu.c:1.55.2.3 src/sys/arch/x86/x86/identcpu.c:1.55.2.4 --- src/sys/arch/x86/x86/identcpu.c:1.55.2.3 Sun Apr 1 08:51:47 2018 +++ src/sys/arch/x86/x86/identcpu.c Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: identcpu.c,v 1.55.2.3 2018/04/01 08:51:47 martin Exp $ */ +/* $NetBSD: identcpu.c,v 1.55.2.4 2018/06/23 11:39:02 martin Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.55.2.3 2018/04/01 08:51:47 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.55.2.4 2018/06/23 11:39:02 martin Exp $"); #include "opt_xen.h" @@ -730,11 +730,59 @@ cpu_probe_old_fpu(struct cpu_info *ci) } #endif +#ifndef XEN +static void +cpu_probe_fpu_leak(struct cpu_info *ci) +{ + /* + * INTEL-SA-00145. Affected CPUs are from Family 6. + */ + if (cpu_vendor != CPUVENDOR_INTEL) { + return; + } + if (CPUID_TO_FAMILY(ci->ci_signature) != 6) { + return; + } + + switch (CPUID_TO_MODEL(ci->ci_signature)) { + /* Atom CPUs are not vulnerable. */ + case 0x1c: /* Pineview */ + case 0x26: /* Lincroft */ + case 0x27: /* Penwell */ + case 0x35: /* Cloverview */ + case 0x36: /* Cedarview */ + case 0x37: /* Baytrail / Valleyview (Silvermont) */ + case 0x4d: /* Avaton / Rangely (Silvermont) */ + case 0x4c: /* Cherrytrail / Brasswell */ + case 0x4a: /* Merrifield */ + case 0x5a: /* Moorefield */ + case 0x5c: /* Goldmont */ + case 0x5f: /* Denverton */ + case 0x7a: /* Gemini Lake */ + break; + + /* Knights CPUs are not vulnerable. */ + case 0x57: /* Knights Landing */ + case 0x85: /* Knights Mill */ + break; + + /* The rest is vulnerable. */ + default: + x86_fpu_eager = true; + break; + } +} +#endif + static void cpu_probe_fpu(struct cpu_info *ci) { u_int descs[4]; +#ifndef XEN + cpu_probe_fpu_leak(ci); +#endif + #ifdef i386 /* amd64 always has fxsave, sse and sse2 */ /* If we have FXSAVE/FXRESTOR, use them. */ if ((ci->ci_feat_val[0] & CPUID_FXSR) == 0) { Index: src/sys/arch/x86/x86/vm_machdep.c diff -u src/sys/arch/x86/x86/vm_machdep.c:1.28.6.3 src/sys/arch/x86/x86/vm_machdep.c:1.28.6.4 --- src/sys/arch/x86/x86/vm_machdep.c:1.28.6.3 Thu Mar 22 16:59:04 2018 +++ src/sys/arch/x86/x86/vm_machdep.c Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: vm_machdep.c,v 1.28.6.3 2018/03/22 16:59:04 martin Exp $ */ +/* $NetBSD: vm_machdep.c,v 1.28.6.4 2018/06/23 11:39:02 martin Exp $ */ /*- * Copyright (c) 1982, 1986 The Regents of the University of California. @@ -80,7 +80,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.28.6.3 2018/03/22 16:59:04 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.28.6.4 2018/06/23 11:39:02 martin Exp $"); #include "opt_mtrr.h" @@ -157,6 +157,10 @@ cpu_lwp_fork(struct lwp *l1, struct lwp /* Copy the PCB from parent. */ memcpy(pcb2, pcb1, sizeof(struct pcb)); + + /* FPU state not installed. */ + pcb2->pcb_fpcpu = NULL; + /* Copy any additional fpu state */ fpu_save_area_fork(pcb2, pcb1); Index: src/sys/arch/x86/x86/x86_machdep.c diff -u src/sys/arch/x86/x86/x86_machdep.c:1.91.4.3 src/sys/arch/x86/x86/x86_machdep.c:1.91.4.4 --- src/sys/arch/x86/x86/x86_machdep.c:1.91.4.3 Sat Jun 9 15:12:21 2018 +++ src/sys/arch/x86/x86/x86_machdep.c Sat Jun 23 11:39:02 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: x86_machdep.c,v 1.91.4.3 2018/06/09 15:12:21 martin Exp $ */ +/* $NetBSD: x86_machdep.c,v 1.91.4.4 2018/06/23 11:39:02 martin Exp $ */ /*- * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi, @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.91.4.3 2018/06/09 15:12:21 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.91.4.4 2018/06/23 11:39:02 martin Exp $"); #include "opt_modular.h" #include "opt_physmem.h" @@ -1201,6 +1201,11 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc sysctl_speculation_init(clog); #endif +#ifndef XEN + void sysctl_eagerfpu_init(struct sysctllog **); + sysctl_eagerfpu_init(clog); +#endif + /* None of these can ever change once the system has booted */ const_sysctl(clog, "fpu_present", CTLTYPE_INT, i386_fpu_present, CPU_FPU_PRESENT);