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.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
src/qemu/qemu_capabilities.c | 39 +++++++++++++++++++
src/qemu/qemu_driver.c | 10 +++++
.../domaincapsdata/qemu_2.12.0-q35.x86_64.xml | 4 +-
.../domaincapsdata/qemu_2.12.0-tcg.x86_64.xml | 4 +-
tests/domaincapsdata/qemu_2.12.0.x86_64.xml | 4 +-
.../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 4 +-
.../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 4 +-
tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 4 +-
tests/testutilsqemu.c | 21 ++++++++++
9 files changed, 82 insertions(+), 12 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 4ffd0a98a2..ddd61ecfc9 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -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;
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ee23e10543..8ee0939295 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -19918,6 +19918,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;
diff --git a/tests/domaincapsdata/qemu_2.12.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_2.12.0-q35.x86_64.xml
index 26816ff066..0dc5995c09 100644
--- a/tests/domaincapsdata/qemu_2.12.0-q35.x86_64.xml
+++ b/tests/domaincapsdata/qemu_2.12.0-q35.x86_64.xml
@@ -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>
diff --git a/tests/domaincapsdata/qemu_2.12.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_2.12.0-tcg.x86_64.xml
index 5840a8b921..575506d852 100644
--- a/tests/domaincapsdata/qemu_2.12.0-tcg.x86_64.xml
+++ b/tests/domaincapsdata/qemu_2.12.0-tcg.x86_64.xml
@@ -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>
diff --git a/tests/domaincapsdata/qemu_2.12.0.x86_64.xml b/tests/domaincapsdata/qemu_2.12.0.x86_64.xml
index 21d1b6946e..c8a5558536 100644
--- a/tests/domaincapsdata/qemu_2.12.0.x86_64.xml
+++ b/tests/domaincapsdata/qemu_2.12.0.x86_64.xml
@@ -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>
diff --git a/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml
index 3415d44019..4595e70f61 100644
--- a/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml
+++ b/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml
@@ -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>
diff --git a/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml
index f58be3af6c..6b85c9c45a 100644
--- a/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml
+++ b/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml
@@ -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>
diff --git a/tests/domaincapsdata/qemu_6.0.0.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0.x86_64.xml
index 0a2615c519..a6fa374211 100644
--- a/tests/domaincapsdata/qemu_6.0.0.x86_64.xml
+++ b/tests/domaincapsdata/qemu_6.0.0.x86_64.xml
@@ -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>
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
index 5bd1d40ad4..7f848f158e 100644
--- a/tests/testutilsqemu.c
+++ b/tests/testutilsqemu.c
@@ -143,6 +143,27 @@ 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) {
+ *ecx = 509;
+ *edx = 451;
+ }
+}
static int
testQemuAddGuest(virCaps *caps,
--
2.33.1
On Fri, Dec 10, 2021 at 16:47:10 +0000, Daniel P. Berrangé wrote:
> 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.
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> src/qemu/qemu_capabilities.c | 39 +++++++++++++++++++
> src/qemu/qemu_driver.c | 10 +++++
> .../domaincapsdata/qemu_2.12.0-q35.x86_64.xml | 4 +-
> .../domaincapsdata/qemu_2.12.0-tcg.x86_64.xml | 4 +-
> tests/domaincapsdata/qemu_2.12.0.x86_64.xml | 4 +-
> .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 4 +-
> .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 4 +-
> tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 4 +-
> tests/testutilsqemu.c | 21 ++++++++++
> 9 files changed, 82 insertions(+), 12 deletions(-)
[...]
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index ee23e10543..8ee0939295 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -19918,6 +19918,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;
Both calls have broken alignment.
[...]
> diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
> index 5bd1d40ad4..7f848f158e 100644
> --- a/tests/testutilsqemu.c
> +++ b/tests/testutilsqemu.c
> @@ -143,6 +143,27 @@ virCapabilitiesHostNUMANewHost(void)
> return virTestCapsBuildNUMATopology(3);
> }
>
> +void
This form of overriding functions looked a bit unorthodox but prior art
is right above, so it's okay.
> +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) {
> + *ecx = 509;
> + *edx = 451;
ecx/edx are unconditionally dereferenced here. Okay at this point but
possibly unextensible. Consider adding pointer checks at least to avoid
coverity moaning.
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
On Tue, Dec 14, 2021 at 11:44:00AM +0100, Peter Krempa wrote:
> On Fri, Dec 10, 2021 at 16:47:10 +0000, Daniel P. Berrangé wrote:
> > 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.
> >
> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> > ---
> > src/qemu/qemu_capabilities.c | 39 +++++++++++++++++++
> > src/qemu/qemu_driver.c | 10 +++++
> > .../domaincapsdata/qemu_2.12.0-q35.x86_64.xml | 4 +-
> > .../domaincapsdata/qemu_2.12.0-tcg.x86_64.xml | 4 +-
> > tests/domaincapsdata/qemu_2.12.0.x86_64.xml | 4 +-
> > .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 4 +-
> > .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 4 +-
> > tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 4 +-
> > tests/testutilsqemu.c | 21 ++++++++++
> > 9 files changed, 82 insertions(+), 12 deletions(-)
>
> [...]
>
> > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> > index ee23e10543..8ee0939295 100644
> > --- a/src/qemu/qemu_driver.c
> > +++ b/src/qemu/qemu_driver.c
> > @@ -19918,6 +19918,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;
>
> Both calls have broken alignment.
This is consistent with the alignment of all existing code
in this method.
> > diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
> > index 5bd1d40ad4..7f848f158e 100644
> > --- a/tests/testutilsqemu.c
> > +++ b/tests/testutilsqemu.c
> > @@ -143,6 +143,27 @@ virCapabilitiesHostNUMANewHost(void)
> > return virTestCapsBuildNUMATopology(3);
> > }
> >
> > +void
>
> This form of overriding functions looked a bit unorthodox but prior art
> is right above, so it's okay.
It is basically relying on the linker method resolution ordering
to have same effect as LD_PRELOAD, without having to jump through
the hoops of creating a preload .so library.
>
> > +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) {
> > + *ecx = 509;
> > + *edx = 451;
>
> ecx/edx are unconditionally dereferenced here. Okay at this point but
> possibly unextensible. Consider adding pointer checks at least to avoid
> coverity moaning.
Hmm, yes will do.
> Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
© 2016 - 2025 Red Hat, Inc.