qemu: report max number of SEV guests

Different CPU generations have different limits on the number
of SEV/SEV-ES guests that can be run. Since both limits come
from the same overall set, there is typically also BIOS config
to set the tradeoff betweeen SEV and SEV-ES guest limits.

This is important information to expose for a mgmt application
scheduling guests to hosts.

Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2021-12-08 14:53:45 -05:00
parent 2150c7c9f7
commit 7826148a72
9 changed files with 84 additions and 12 deletions

View File

@ -1897,6 +1897,8 @@ virQEMUCapsSEVInfoCopy(virSEVCapability **dst,
tmp->cbitpos = src->cbitpos;
tmp->reduced_phys_bits = src->reduced_phys_bits;
tmp->max_guests = src->max_guests;
tmp->max_es_guests = src->max_es_guests;
*dst = g_steal_pointer(&tmp);
return 0;
@ -3286,6 +3288,31 @@ virQEMUCapsProbeQMPGICCapabilities(virQEMUCaps *qemuCaps,
}
static void
virQEMUCapsGetSEVMaxGuests(virSEVCapability *caps)
{
/*
* From Secure Encrypted Virtualization API v0.24, section 6.19.1
*
* If the guest is SEV-ES enabled, then the ASID must be at least
* 1h and at most (MIN_SEV_ASID-1). If the guest is not SEV-ES
* enabled, then the ASID must be at least MIN_SEV_ASID and at
* most the maximum SEV ASID available. The MIN_SEV_ASID value
* is discovered by CPUID Fn8000_001F[EDX]. The maximum SEV ASID
* available is discovered by CPUID Fn8000_001F[ECX].
*/
uint32_t min_asid, max_asid;
virHostCPUX86GetCPUID(0x8000001F, 0, NULL, NULL,
&max_asid, &min_asid);
if (max_asid != 0 && min_asid != 0) {
caps->max_guests = max_asid - min_asid + 1;
caps->max_es_guests = min_asid - 1;
} else {
caps->max_guests = caps->max_es_guests = 0;
}
}
static int
virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps,
qemuMonitor *mon)
@ -3305,6 +3332,8 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps,
return 0;
}
virQEMUCapsGetSEVMaxGuests(caps);
virSEVCapabilitiesFree(qemuCaps->sevCapabilities);
qemuCaps->sevCapabilities = caps;
return 0;
@ -4084,6 +4113,14 @@ virQEMUCapsParseSEVInfo(virQEMUCaps *qemuCaps, xmlXPathContextPtr ctxt)
return -1;
}
/* We probe this every time because the values
* can change on every reboot via firmware
* config tunables. It is cheap to query so
* lack of caching is a non-issue
*/
virQEMUCapsGetSEVMaxGuests(sev);
qemuCaps->sevCapabilities = g_steal_pointer(&sev);
return 0;
}
@ -6344,6 +6381,8 @@ virQEMUCapsFillDomainFeatureSEVCaps(virQEMUCaps *qemuCaps,
domCaps->sev->cert_chain = g_strdup(cap->cert_chain);
domCaps->sev->cbitpos = cap->cbitpos;
domCaps->sev->reduced_phys_bits = cap->reduced_phys_bits;
domCaps->sev->max_guests = cap->max_guests;
domCaps->sev->max_es_guests = cap->max_es_guests;
}

View File

@ -19917,6 +19917,16 @@ qemuGetSEVInfoToParams(virQEMUCaps *qemuCaps,
sev->reduced_phys_bits) < 0)
goto cleanup;
if (virTypedParamsAddUInt(&sevParams, &n, &maxpar,
VIR_NODE_SEV_MAX_GUESTS,
sev->max_guests) < 0)
goto cleanup;
if (virTypedParamsAddUInt(&sevParams, &n, &maxpar,
VIR_NODE_SEV_MAX_ES_GUESTS,
sev->max_es_guests) < 0)
goto cleanup;
*params = g_steal_pointer(&sevParams);
*nparams = n;
return 0;

View File

@ -205,8 +205,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -215,8 +215,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -205,8 +205,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -227,8 +227,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -233,8 +233,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -227,8 +227,8 @@
<sev supported='yes'>
<cbitpos>47</cbitpos>
<reducedPhysBits>1</reducedPhysBits>
<maxGuests>0</maxGuests>
<maxESGuests>0</maxESGuests>
<maxGuests>59</maxGuests>
<maxESGuests>450</maxESGuests>
</sev>
</features>
</domainCapabilities>

View File

@ -143,6 +143,29 @@ virCapabilitiesHostNUMANewHost(void)
return virTestCapsBuildNUMATopology(3);
}
void
virHostCPUX86GetCPUID(uint32_t leaf,
uint32_t extended,
uint32_t *eax,
uint32_t *ebx,
uint32_t *ecx,
uint32_t *edx)
{
if (eax)
*eax = 0;
if (ebx)
*ebx = 0;
if (ecx)
*ecx = 0;
if (edx)
*edx = 0;
if (leaf == 0x8000001F && extended == 0) {
if (ecx)
*ecx = 509;
if (edx)
*edx = 451;
}
}
static int
testQemuAddGuest(virCaps *caps,