From d4005609f3806f3ee4ad7e39cba0c887baf462a5 Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Fri, 8 Jun 2018 09:40:51 -0500 Subject: [PATCH] qemu: Provide support to query the SEV capability QEMU version >= 2.12 provides support for launching an encrypted VMs on AMD x86 platform using Secure Encrypted Virtualization (SEV) feature. This patch adds support to query the SEV capability from the qemu. Signed-off-by: Brijesh Singh Reviewed-by: Erik Skultety --- src/conf/domain_capabilities.c | 12 +++ src/conf/domain_capabilities.h | 12 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 37 +++++++++ src/qemu/qemu_capabilities.h | 4 +- src/qemu/qemu_capspriv.h | 4 + src/qemu/qemu_monitor.c | 10 +++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 79 +++++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 + .../caps_2.12.0.x86_64.replies | 10 +++ .../caps_2.12.0.x86_64.xml | 3 +- 12 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index c20358e916..3589777524 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -67,6 +67,18 @@ virDomainCapsStringValuesFree(virDomainCapsStringValuesPtr values) } +void +virSEVCapabilitiesFree(virSEVCapability *cap) +{ + if (!cap) + return; + + VIR_FREE(cap->pdh); + VIR_FREE(cap->cert_chain); + VIR_FREE(cap); +} + + static void virDomainCapsDispose(void *obj) { diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index b0eb4aa7e3..56c1903cf4 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -137,6 +137,15 @@ struct _virDomainCapsCPU { virDomainCapsCPUModelsPtr custom; }; +typedef struct _virSEVCapability virSEVCapability; +typedef virSEVCapability *virSEVCapabilityPtr; +struct _virSEVCapability { + char *pdh; + char *cert_chain; + unsigned int cbitpos; + unsigned int reduced_phys_bits; +}; + struct _virDomainCaps { virObjectLockable parent; @@ -202,4 +211,7 @@ int virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum, void virDomainCapsEnumClear(virDomainCapsEnumPtr capsEnum); char * virDomainCapsFormat(virDomainCapsPtr const caps); + +void +virSEVCapabilitiesFree(virSEVCapability *capabilities); #endif /* __DOMAIN_CAPABILITIES_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2245101590..ea24f2847c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -185,6 +185,7 @@ virDomainCapsEnumClear; virDomainCapsEnumSet; virDomainCapsFormat; virDomainCapsNew; +virSEVCapabilitiesFree; # conf/domain_conf.h diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index a673709255..8b3ffe1afe 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -497,6 +497,9 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "tpm-emulator", "mch", "mch.extended-tseg-mbytes", + + /* 310 */ + "sev-guest", ); @@ -563,6 +566,8 @@ struct _virQEMUCaps { size_t ngicCapabilities; virGICCapability *gicCapabilities; + virSEVCapability *sevCapabilities; + virQEMUCapsHostCPUData kvmCPU; virQEMUCapsHostCPUData tcgCPU; }; @@ -1135,6 +1140,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "vmgenid", QEMU_CAPS_DEVICE_VMGENID }, { "vhost-vsock-device", QEMU_CAPS_DEVICE_VHOST_VSOCK }, { "mch", QEMU_CAPS_DEVICE_MCH }, + { "sev-guest", QEMU_CAPS_SEV_GUEST }, }; static struct virQEMUCapsStringFlags virQEMUCapsDevicePropsVirtioBalloon[] = { @@ -2078,6 +2084,16 @@ virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps, } +void +virQEMUCapsSetSEVCapabilities(virQEMUCapsPtr qemuCaps, + virSEVCapability *capabilities) +{ + virSEVCapabilitiesFree(qemuCaps->sevCapabilities); + + qemuCaps->sevCapabilities = capabilities; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon) @@ -2665,6 +2681,21 @@ virQEMUCapsProbeQMPGICCapabilities(virQEMUCapsPtr qemuCaps, } +static int +virQEMUCapsProbeQMPSEVCapabilities(virQEMUCapsPtr qemuCaps, + qemuMonitorPtr mon) +{ + virSEVCapability *caps = NULL; + + if (qemuMonitorGetSEVCapabilities(mon, &caps) < 0) + return -1; + + virQEMUCapsSetSEVCapabilities(qemuCaps, caps); + + return 0; +} + + bool virQEMUCapsCPUFilterFeatures(const char *name, void *opaque) @@ -4064,6 +4095,12 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps, virQEMUCapsClear(qemuCaps, QEMU_CAPS_DEVICE_VFIO_CCW); } + /* Probe for SEV capabilities */ + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SEV_GUEST)) { + if (virQEMUCapsProbeQMPSEVCapabilities(qemuCaps, mon) < 0) + virQEMUCapsClear(qemuCaps, QEMU_CAPS_SEV_GUEST); + } + ret = 0; cleanup: return ret; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 884b40650c..f80da918cf 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -482,6 +482,9 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_DEVICE_MCH, /* Northbridge in q35 machine types */ QEMU_CAPS_MCH_EXTENDED_TSEG_MBYTES, /* -global mch.extended-tseg-mbytes */ + /* 310 */ + QEMU_CAPS_SEV_GUEST, /* -object sev-guest,... */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -615,5 +618,4 @@ bool virQEMUCapsGuestIsNative(virArch host, bool virQEMUCapsCPUFilterFeatures(const char *name, void *opaque); - #endif /* __QEMU_CAPABILITIES_H__*/ diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h index 4b7a04ad4b..cb5e0dd9a9 100644 --- a/src/qemu/qemu_capspriv.h +++ b/src/qemu/qemu_capspriv.h @@ -90,6 +90,10 @@ virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps, virGICCapability *capabilities, size_t ncapabilities); +void +virQEMUCapsSetSEVCapabilities(virQEMUCapsPtr qemuCaps, + virSEVCapability *capabilities); + int virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 215135aa3e..fd6bce91b5 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3849,6 +3849,16 @@ qemuMonitorGetGICCapabilities(qemuMonitorPtr mon, } +int +qemuMonitorGetSEVCapabilities(qemuMonitorPtr mon, + virSEVCapability **capabilities) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetSEVCapabilities(mon, capabilities); +} + + int qemuMonitorNBDServerStart(qemuMonitorPtr mon, const char *host, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d01266ff86..818bd20a25 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -711,6 +711,9 @@ int qemuMonitorSetMigrationCapabilities(qemuMonitorPtr mon, int qemuMonitorGetGICCapabilities(qemuMonitorPtr mon, virGICCapability **capabilities); +int qemuMonitorGetSEVCapabilities(qemuMonitorPtr mon, + virSEVCapability **capabilities); + typedef enum { QEMU_MONITOR_MIGRATE_BACKGROUND = 1 << 0, QEMU_MONITOR_MIGRATE_NON_SHARED_DISK = 1 << 1, /* migration with non-shared storage with full disk copy */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e8a46d2ec3..ba0da9a483 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6401,6 +6401,85 @@ qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon, return ret; } + +int +qemuMonitorJSONGetSEVCapabilities(qemuMonitorPtr mon, + virSEVCapability **capabilities) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr caps; + virSEVCapability *capability = NULL; + const char *pdh = NULL, *cert_chain = NULL; + unsigned int cbitpos, reduced_phys_bits; + + *capabilities = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-sev-capabilities", + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + caps = virJSONValueObjectGetObject(reply, "return"); + + if (virJSONValueObjectGetNumberUint(caps, "cbitpos", &cbitpos) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sev-capabilities reply was missing" + " 'cbitpos' field")); + goto cleanup; + } + + if (virJSONValueObjectGetNumberUint(caps, "reduced-phys-bits", + &reduced_phys_bits) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sev-capabilities reply was missing" + " 'reduced-phys-bits' field")); + goto cleanup; + } + + if (!(pdh = virJSONValueObjectGetString(caps, "pdh"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sev-capabilities reply was missing" + " 'pdh' field")); + goto cleanup; + } + + if (!(cert_chain = virJSONValueObjectGetString(caps, "cert-chain"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sev-capabilities reply was missing" + " 'cert-chain' field")); + goto cleanup; + } + + if (VIR_ALLOC(capability) < 0) + goto cleanup; + + if (VIR_STRDUP(capability->pdh, pdh) < 0) + goto cleanup; + + if (VIR_STRDUP(capability->cert_chain, cert_chain) < 0) + goto cleanup; + + capability->cbitpos = cbitpos; + capability->reduced_phys_bits = reduced_phys_bits; + VIR_STEAL_PTR(*capabilities, capability); + ret = 0; + + cleanup: + virSEVCapabilitiesFree(capability); + virJSONValueFree(cmd); + virJSONValueFree(reply); + + return ret; +} + static virJSONValuePtr qemuMonitorJSONBuildInetSocketAddress(const char *host, const char *port) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 2ae0faad74..4c10574673 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -152,6 +152,9 @@ int qemuMonitorJSONSetMigrationCapabilities(qemuMonitorPtr mon, int qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon, virGICCapability **capabilities); +int qemuMonitorJSONGetSEVCapabilities(qemuMonitorPtr mon, + virSEVCapability **capabilities); + int qemuMonitorJSONMigrate(qemuMonitorPtr mon, unsigned int flags, const char *uri); diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.replies index 78e1b450cd..ddee9b9fb1 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.replies @@ -19038,6 +19038,16 @@ "id": "libvirt-52" } +{ + "return" : { + "reduced-phys-bits": 1, + "cbitpos": 47, + "cert-chain": "AQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAA", + "pdh": "AQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAA" + }, + "id": "libvirt-52" +} + { "return": { }, diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml index 2afd7adc60..0c38826652 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml @@ -210,9 +210,10 @@ + 2011090 0 - 391586 + 391832 v2.12.0-rc0 x86_64