Index | Thread | Search

From:
hshoexer <hshoexer@yerbouti.franken.de>
Subject:
Re: vmm(4): use SEV ASID bounds when allocating SVM ASIDs
To:
tech@openbsd.org
Date:
Mon, 15 Jun 2026 10:57:46 +0200

Download raw body.

Thread
Hi,

On Sun, Jun 14, 2026 at 02:25:53PM +0000, Chris Cunningham wrote:
> Hello,
> 
> I have a couple of patches that I've been running on a 7.8 host for a
> while now, and I think they may be addressing issues that still exist
> at top-of-tree. Just in case you'd rather have one patch per email,
> I'll send the second one separately.
> 
> This first one is about vmm(4). On an AMD Ryzen Threadripper PRO 9995WX
> box, every ordinary non-SEV VM refused to start, always with:
> 
> vmm_alloc_vpid_vcpu: no available ASIDs
> 
> The machine is:
> 
> ASUS Pro WS WRX90E-SAGE SE
> AMD Ryzen Threadripper PRO 9995WX
> 512GB RAM
> 
> After some digging it came down to CPUID leaf 0x8000001f. Here's the
> cpu0 line from dmesg:
> 
> cpu0: cpuid 8000001F eax=cffffffb<SME,SEV,SEVES,SEVSNP,VMPL,RMPQUERY,VMPLSSS,SECTSC,TSCAUXVIRT,HWECACHECOH,REQ64BITHOST,RESTINJ,ALTINJ,DBGSTSW,IBSDISALLOW,VTE,VMGEXITPARAM,VTOMMSR,IBSVIRT,VMSARPROT,SMTPROT> ecx=3ee edx=cf680a81
> 
> ECX reports 1006 encrypted guest ASIDs, which looks sane, but EDX
> (MinSevNoEsAsid) comes back much larger than that. NASID from CPUID
> 0x8000000a EBX is only 32768. EDX also isn't stable across CPUs/boots
> on this box -- I've seen 0x823c67d2, 0x9c866294 and 0xcf680a81 at
> different times. My best guess is that it's because the board's AMD
> PSP/CCP shows up "not configured" in dmesg, so nothing ever populates
> EDX with a real boundary, but I haven't confirmed that part.

Is SEV enabled in the firmware?

> The trouble is that we store EDX straight into amd64_min_noes_asid and
> then use it as the minimum ASID for every non-SEV-ES guest, ordinary
> non-SEV guests included. With a bogus value that's non-zero and well
> past the range vmm actually scans, vmm_alloc_vpid_vcpu() never finds a
> free ASID and bails out.
> 
> The diff below keeps ECX as the upper bound of the encrypted-ASID
> range, and only trusts EDX as the lower bound for plain SEV guests when
> it's actually in range. Ordinary non-SEV guests now start at ECX + 1.
> If the encrypted range somehow covers everything vmm would scan,
> allocation just fails rather than dipping into ASIDs meant for
> encrypted guests.
> 
> With this applied the same host happily starts ordinary vmd guests
> again.
> 
> Thanks,
> Chris
> 
> diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c
> index 51e8344d573..67dafb40e63 100644
> --- a/sys/arch/amd64/amd64/identcpu.c
> +++ b/sys/arch/amd64/amd64/identcpu.c
> @@ -67,6 +67,7 @@ int cpuspeed;
> 
> int amd64_has_xcrypt;
> int amd64_pos_cbit; /* C bit position for SEV */
> +int amd64_num_sev_asids;
> int amd64_min_noes_asid;
> int has_rdrand;
> int has_rdseed;
> @@ -711,7 +712,12 @@ identifycpu(struct cpu_info *ci)
> 'd', CPUID_MEMBER(ci_feature_amdsev_edx),
> CPUID_AMDSEV_EDX_BITS);
> amd64_pos_cbit = (ci->ci_feature_amdsev_ebx & 0x3f);
> - amd64_min_noes_asid = ci->ci_feature_amdsev_edx;
> + amd64_num_sev_asids = ci->ci_feature_amdsev_ecx;
> + if (ci->ci_feature_amdsev_edx >= 1 &&
> + ci->ci_feature_amdsev_edx <= ci->ci_feature_amdsev_ecx)
> + amd64_min_noes_asid = ci->ci_feature_amdsev_edx;
> + else
> + amd64_min_noes_asid = 0;
> if (cpu_sev_guestmode && CPU_IS_PRIMARY(ci))
> printf("\n%s: SEV%s guest mode", ci->ci_dev->dv_xname,
> ISSET(cpu_sev_guestmode, SEV_STAT_ES_ENABLED) ?
> diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
> index 787b65e29e1..2b0e02c2095 100644
> --- a/sys/arch/amd64/amd64/vmm_machdep.c
> +++ b/sys/arch/amd64/amd64/vmm_machdep.c
> @@ -6926,7 +6926,17 @@ vmm_alloc_vpid_vcpu(uint16_t *vpid, struct vcpu *vcpu)
> struct vmm_softc *sc = vmm_softc;
> 
> rw_enter_write(&vmm_softc->vpid_lock);
> - if (vcpu == NULL || vcpu->vc_seves || amd64_min_noes_asid == 0)
> + if (vcpu == NULL || vcpu->vc_seves)
> + minasid = 1;
> + else if (vcpu->vc_sev && amd64_min_noes_asid != 0)
> + minasid = amd64_min_noes_asid;
> + else if (!vcpu->vc_sev && amd64_num_sev_asids != 0) {
> + if (amd64_num_sev_asids < sc->max_vpid)
> + minasid = amd64_num_sev_asids + 1;
> + else
> + minasid = sc->max_vpid + 1;
> + }
> + else if (amd64_min_noes_asid == 0)
> minasid = 1;
> else
> minasid = amd64_min_noes_asid;
> diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h
> index 15423f5d5f2..b771214d400 100644
> --- a/sys/arch/amd64/include/cpu.h
> +++ b/sys/arch/amd64/include/cpu.h
> @@ -419,6 +419,7 @@ void identifycpu(struct cpu_info *);
> int cpu_amd64speed(int *);
> extern int cpuspeed;
> extern int amd64_pos_cbit;
> +extern int amd64_num_sev_asids;
> extern int amd64_min_noes_asid;
> /* machdep.c */