From: hshoexer 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 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 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 */