On 2/20/24 07:31, Takashi Kajinami wrote:
This introduces the new "model" field in sev elements,
returned by
domain capabilities API, so that client can ensure SEV-ES is available
in this hypervisor.
Signed-off-by: Takashi Kajinami <kajinamit(a)oss.nttdata.com>
---
docs/formatdomaincaps.rst | 5 ++
src/conf/domain_capabilities.c | 2 +
src/conf/domain_capabilities.h | 1 +
src/conf/domain_conf.c | 7 +++
src/conf/domain_conf.h | 8 ++++
src/qemu/qemu_capabilities.c | 84 +++++++++++++++++++++++++---------
6 files changed, 85 insertions(+), 22 deletions(-)
diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst
index ef752a0f3a..78a6f8736f 100644
--- a/docs/formatdomaincaps.rst
+++ b/docs/formatdomaincaps.rst
@@ -753,6 +753,11 @@ in domain XML <formatdomain.html#launch-security>`__
``maxESGuests``
The maximum number of SEV-ES guests that can be launched on the host. This
value may be configurable in the firmware for some hosts.
+``cpu0Id``
+ ID of CPU0, which is used to get the signed Chip Endorsement Key (CEK) of
+ the CPU of AMD system from AMD's Key Distribution Service (KDS).
+``model``
+ Available SEV models.
SGX capabilities
^^^^^^^^^^^^^^^^
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 68eb3c9797..26d9b0a21c 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -654,6 +654,8 @@ virDomainCapsFeatureSEVFormat(virBuffer *buf,
if (sev->cpu0_id != NULL)
virBufferAsprintf(buf, "<cpu0Id>%s</cpu0Id>\n",
sev->cpu0_id);
+ ENUM_PROCESS(sev, model, virDomainSevModelTypeToString);
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</sev>\n");
}
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index fadc30cdd7..1a84ea6101 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -213,6 +213,7 @@ struct _virSEVCapability {
unsigned int reduced_phys_bits;
unsigned int max_guests;
unsigned int max_es_guests;
+ virDomainCapsEnum model;
};
typedef struct _virSGXSection virSGXSection;
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 3597959e33..cf0077d584 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1509,6 +1509,13 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
"s390-pv",
);
+VIR_ENUM_IMPL(virDomainSevModel,
+ VIR_DOMAIN_SEV_MODEL_LAST,
+ "",
+ "sev",
+ "sev-es",
+);
+
typedef enum {
VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE,
VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index c7e5005b3b..a06fde1032 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2854,6 +2854,13 @@ typedef enum {
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
} virDomainLaunchSecurity;
+typedef enum {
+ VIR_DOMAIN_SEV_MODEL_NONE,
+ VIR_DOMAIN_SEV_MODEL_SEV,
+ VIR_DOMAIN_SEV_MODEL_SEV_ES,
There's SEV SNP now too.
+
+ VIR_DOMAIN_SEV_MODEL_LAST,
+} virDomainSevModel;
struct _virDomainSEVDef {
char *dh_cert;
@@ -4237,6 +4244,7 @@ VIR_ENUM_DECL(virDomainCryptoType);
VIR_ENUM_DECL(virDomainCryptoBackend);
VIR_ENUM_DECL(virDomainShmemModel);
VIR_ENUM_DECL(virDomainShmemRole);
+VIR_ENUM_DECL(virDomainSevModel);
VIR_ENUM_DECL(virDomainLaunchSecurity);
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState);
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index e383d85920..d264c3128c 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -1881,6 +1881,7 @@ virQEMUCapsSEVInfoCopy(virSEVCapability **dst,
tmp->reduced_phys_bits = src->reduced_phys_bits;
tmp->max_guests = src->max_guests;
tmp->max_es_guests = src->max_es_guests;
+ tmp->model = src->model;
*dst = g_steal_pointer(&tmp);
}
@@ -3402,6 +3403,62 @@ virQEMUCapsGetSEVMaxGuests(virSEVCapability *caps)
}
}
+
+/*
+ * Check whether AMD Secure Encrypted Virtualization (x86) is enabled
+ */
+static bool
+virQEMUCapsKVMSupportsSecureGuestSEV(void)
+{
+ g_autofree char *modValue = NULL;
+
+ if (virFileReadValueString(&modValue,
"/sys/module/kvm_amd/parameters/sev") < 0)
+ return false;
+
+ if (modValue[0] != '1' && modValue[0] != 'Y' &&
modValue[0] != 'y')
+ return false;
+
+ if (virFileExists(QEMU_DEV_SEV))
+ return true;
+
+ return false;
+}
+
+
+/*
+ * Check whether AMD Secure Encrypted Virtualization-Encrypted State (x86) is enabled
+ */
+static bool
+virQEMUCapsKVMSupportsSecureGuestSEVES(void)
+{
+ g_autofree char *modValue = NULL;
+
+ if (virFileReadValueString(&modValue,
"/sys/module/kvm_amd/parameters/sev_es") < 0)
+ return false;
+
+ if (modValue[0] != '1' && modValue[0] != 'Y' &&
modValue[0] != 'y')
+ return false;
+
+ if (virFileExists(QEMU_DEV_SEV))
+ return true;
+
+ return false;
+}
These two functions differ only in the path they query. Now, I'm not
sure the kernel module can have "Y" without /dev/sev existing.
Anyway, I think one of these function should be turned into
static bool
func(const char *path)
{
virFileReadValueString(&modValue, path);
if (modValue[0] != 'y' ...)
return false;
return true;
}
and then ...
+
+
+static void
+virQEMUCapsGetSEVModel(virSEVCapability *caps)
+{
+ caps->model.report = true;
.. here we can have a static array of tuples:
const char *params[VIR_DOMAIN_SEV_MODEL_LAST] = {
[VIR_DOMAIN_SEV_MODEL_SEV] = "/sys/module/kvm_amd/parameters/sev",
[VIR_DOMAIN_SEV_MODEL_SEV_ES] = "/sys/module/kvm_amd/parameters/sev_es",
};
size_t i;
caps->model.report = true;
for (i = 0; i < VIR_DOMAIN_SEV_MODEL_LAST; i++) {
if (virQEMUCapsKVMSupportsSecureGuestSEVES(params[i]))
VIR_DOMAIN_CAPS_ENUM_SET(caps->model, i);
}
Or something among those lines.
Michal