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 be5cfff8fe..aae622ea5d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -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; 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 @@ 47 1 - 0 - 0 + 59 + 450 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 @@ 47 1 - 0 - 0 + 59 + 450 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 @@ 47 1 - 0 - 0 + 59 + 450 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 @@ 47 1 - 0 - 0 + 59 + 450 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 @@ 47 1 - 0 - 0 + 59 + 450 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 @@ 47 1 - 0 - 0 + 59 + 450 diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 5bd1d40ad4..7b19575d8b 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -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,