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 <brijesh.singh@amd.com>
Reviewed-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Brijesh Singh 2018-06-08 09:40:51 -05:00 committed by Erik Skultety
parent 2cbdf303dd
commit d4005609f3
12 changed files with 176 additions and 2 deletions

View File

@ -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)
{

View File

@ -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__ */

View File

@ -185,6 +185,7 @@ virDomainCapsEnumClear;
virDomainCapsEnumSet;
virDomainCapsFormat;
virDomainCapsNew;
virSEVCapabilitiesFree;
# conf/domain_conf.h

View File

@ -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;

View File

@ -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__*/

View File

@ -90,6 +90,10 @@ virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps,
virGICCapability *capabilities,
size_t ncapabilities);
void
virQEMUCapsSetSEVCapabilities(virQEMUCapsPtr qemuCaps,
virSEVCapability *capabilities);
int
virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps,
qemuMonitorPtr mon,

View File

@ -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,

View File

@ -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 */

View File

@ -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)

View File

@ -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);

View File

@ -19038,6 +19038,16 @@
"id": "libvirt-52"
}
{
"return" : {
"reduced-phys-bits": 1,
"cbitpos": 47,
"cert-chain": "AQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAA",
"pdh": "AQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAAAQAAAAAOAAA"
},
"id": "libvirt-52"
}
{
"return": {
},

View File

@ -210,9 +210,10 @@
<flag name='tpm-emulator'/>
<flag name='mch'/>
<flag name='mch.extended-tseg-mbytes'/>
<flag name='sev-guest'/>
<version>2011090</version>
<kvmVersion>0</kvmVersion>
<microcodeVersion>391586</microcodeVersion>
<microcodeVersion>391832</microcodeVersion>
<package>v2.12.0-rc0</package>
<arch>x86_64</arch>
<hostCPU type='kvm' model='base' migratability='yes'>