On Wed, Sep 30, 2026 at 09:44:34PM +0200, Sebastian Albert wrote:
> >Synopsis:      amd64: GPF panic at boot on KVM guests lacking MSR_DE_CFG
> (AMD family 17h)
> >Category:      amd64
> >Environment:
>         System      : OpenBSD 7.9
>         Details     : OpenBSD 7.9 (GENERIC.MP) #15: Sun Sep 27 02:47:36 MDT
> 2026
>  [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> 
>         Architecture: OpenBSD.amd64
>         Machine     : amd64
> >Description:
> OpenBSD 7.9/amd64 (and, judging from the source, 8.0 as well) panics
> very early during boot on a KVM-based VPS (hoster 1blu.de, Virtuozzo)
> with an AMD EPYC (Zen 1) CPU. Both bsd.rd from install79.iso and
> miniroot79.img fail the same way, before the installer starts:
> 
>   fatal protection fault in supervisor mode
>   trap type 4 code 0 rip ... cs 8 rflags ... cr2 0 cpl e
>   panic: trap type 4, code=0, pc=...
> 
> CPU as seen by a FreeBSD 15.1 guest on the same VM:
> 
>   Origin="AuthenticAMD"  Id=0x800f12  Family=0x17  Model=0x1 Stepping=2
>   Features2=...<...,HV>
>   Hypervisor: Origin = "KVMKVMKVM"
> 
> The hypervisor does not implement MSR_DE_CFG (0xc0011029). Reading it
> from the FreeBSD guest faults:
> 
>   # cpucontrol -m 0xc0011029 /dev/cpuctl0
>   cpucontrol: ioctl(/dev/cpuctl0, CPUCTL_RDMSR (0xc0011029)): Bad address
> 
> In cpu_init() (sys/arch/amd64/amd64/cpu.c), the "Mitigation G-2"
> block reads MSR_DE_CFG unconditionally on all AMD families >= 10h
> (except 11h). The two newer MSR blocks below it (Zenbleed and FPDSS)
> already skip the access when CPUIDECX_HV is set, but the G-2 block
> does not, so the unguarded rdmsr() raises #GP and the kernel panics.
> 
> FreeBSD and Linux boot fine on the same VM, since they access this MSR
> in a fault-tolerant way.
> 
> The hoster declined to change the virtual CPU model.
> 
> Note: the system information attached by sendbug is from a different
> (working) machine, since OpenBSD cannot be booted on the affected VM.
> 
> >How-To-Repeat:
> 
> Boot bsd.rd (install79.iso or miniroot79.img, amd64) on a KVM guest
> with an AMD family 17h CPU where the hypervisor does not provide
> MSR_DE_CFG (0xc0011029), e.g. a 1blu.de "VPS R24" instance.
> The kernel panics during CPU identification with trap type 4.
> 
> Whether the MSR is available can be checked from another guest OS,
> e.g. FreeBSD: cpucontrol -m 0xc0011029 /dev/cpuctl0
> 
> >Fix:
> Read MSR_DE_CFG with rdmsr_safe() so the mitigation is still applied
> where the MSR is available (bare metal, or hypervisors that emulate
> it) and is skipped where the access faults:
> 
> File sys/arch/amd64/amd64/cpu.c
> 
>           * This MSR is available on all AMD families >= 10h, except 11h
>           * where LFENCE is always serializing.
> +         * Hypervisors may not implement it, so read it carefully.
>           */
> -        if (family >= 0x10 && family != 0x11) {
> -            nmsr = msr = rdmsr(MSR_DE_CFG);
> -            nmsr |= DE_CFG_SERIALIZE_LFENCE;
> +        if (family >= 0x10 && family != 0x11 &&
> +            rdmsr_safe(MSR_DE_CFG, &msr) == 0) {
> +            nmsr = msr | DE_CFG_SERIALIZE_LFENCE;
>              if (msr != nmsr)
>                  wrmsr(MSR_DE_CFG, nmsr);
>          }
> 
> An alternative would be to add a (cpu_ecxfeature & CPUIDECX_HV) == 0
> check, as done for the Zenbleed and FPDSS blocks, but that would drop
> the mitigation on hypervisors that do implement the MSR.

The limited AMD documentation on mitigations does not mention
hypervisors at all.

It seems we can only assume hypervisors implement all workarounds.
And don't implement most MSRs.

Index: sys/arch/amd64/amd64/cpu.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/cpu.c,v
diff -u -p -r1.207 cpu.c
--- sys/arch/amd64/amd64/cpu.c  28 Sep 2026 04:50:24 -0000      1.207
+++ sys/arch/amd64/amd64/cpu.c  1 Oct 2026 07:26:15 -0000
@@ -1287,7 +1287,8 @@ cpu_fix_msrs(struct cpu_info *ci)
                 * This MSR is available on all AMD families >= 10h, except 11h
                 * where LFENCE is always serializing.
                 */
-               if (family >= 0x10 && family != 0x11) {
+               if (family >= 0x10 && family != 0x11 &&
+                   (cpu_ecxfeature & CPUIDECX_HV) == 0) {
                        nmsr = msr = rdmsr(MSR_DE_CFG);
                        nmsr |= DE_CFG_SERIALIZE_LFENCE;
                        if (msr != nmsr)
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
diff -u -p -r1.680 machdep.c
--- sys/arch/i386/i386/machdep.c        14 May 2026 01:39:38 -0000      1.680
+++ sys/arch/i386/i386/machdep.c        1 Oct 2026 07:26:19 -0000
@@ -2013,7 +2013,8 @@ identifycpu(struct cpu_info *ci)
         * where LFENCE is always serializing.
         */
        if (!strcmp(cpu_vendor, "AuthenticAMD")) {
-               if (ci->ci_family >= 0x10 && ci->ci_family != 0x11) {
+               if (ci->ci_family >= 0x10 && ci->ci_family != 0x11 &&
+                   (cpu_ecxfeature & CPUIDECX_HV) == 0) {
                        nmsr = msr = rdmsr(MSR_DE_CFG);
                        nmsr |= DE_CFG_SERIALIZE_LFENCE;
                        if (msr != nmsr)

Reply via email to