1.Add SGX feature in domain capabilities 2.Get sgx capabilities by query-sgx-capabilities 3.Transfer the B to KB for epc_size 4.Delete sgx1 and sgx2 Signed-off-by: Haibin Huang <haibin.huang@xxxxxxxxx> --- docs/schemas/domaincaps.rng | 20 +++++ src/conf/domain_capabilities.c | 29 +++++++ src/conf/domain_capabilities.h | 13 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 139 +++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 6 ++ src/qemu/qemu_monitor.c | 10 +++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 87 +++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 + 10 files changed, 311 insertions(+) diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng index 325581476d..0dc97b29bc 100644 --- a/docs/schemas/domaincaps.rng +++ b/docs/schemas/domaincaps.rng @@ -219,6 +219,9 @@ <optional> <ref name='sev'/> </optional> + <optional> + <ref name='sgx'/> + </optional> </element> </define> @@ -267,6 +270,23 @@ </element> </define> + <define name='sgx'> + <element name='sgx'> + <ref name='supported'/> + <optional> + <element name='flc'> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </element> + <element name='epc_size'> + <ref name='scaledInteger'/> + </element> + </optional> + </element> + </define> + <define name='value'> <zeroOrMore> <element name='value'> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index d61108e125..8024200951 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -91,6 +91,16 @@ virSEVCapabilitiesFree(virSEVCapability *cap) } +void +virSGXCapabilitiesFree(virSGXCapability *cap) +{ + if (!cap) + return; + + VIR_FREE(cap); +} + + static void virDomainCapsDispose(void *obj) { @@ -101,6 +111,7 @@ virDomainCapsDispose(void *obj) virObjectUnref(caps->cpu.custom); virCPUDefFree(caps->cpu.hostModel); virSEVCapabilitiesFree(caps->sev); + virSGXCapabilitiesFree(caps->sgx); virDomainCapsStringValuesFree(&caps->os.loader.values); } @@ -564,6 +575,23 @@ virDomainCapsFeatureSEVFormat(virBufferPtr buf, return; } +static void +virDomainCapsFeatureSGXFormat(virBufferPtr buf, + virSGXCapabilityPtr const sgx) +{ + if (!sgx) { + virBufferAddLit(buf, "<sgx supported='no'/>\n"); + } else { + virBufferAddLit(buf, "<sgx supported='yes'>\n"); + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<flc>%s</flc>\n", sgx->flc ? "yes" : "no"); + virBufferAsprintf(buf, "<epc_size unit='KiB'>%llu</epc_size>\n", sgx->epc_size); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</sgx>\n"); + } + + return; +} static void virDomainCapsFormatFeatures(const virDomainCaps *caps, @@ -584,6 +612,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps, } virDomainCapsFeatureSEVFormat(&childBuf, caps->sev); + virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx); virXMLFormatElement(buf, "features", NULL, &childBuf); } diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 685d5e2a44..0b2447e81f 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -150,6 +150,13 @@ struct _virDomainCapsCPU { virDomainCapsCPUModelsPtr custom; }; +typedef struct _virSGXCapability virSGXCapability; +typedef virSGXCapability *virSGXCapabilityPtr; +struct _virSGXCapability { + bool flc; + unsigned long long epc_size; +}; + typedef struct _virSEVCapability virSEVCapability; typedef virSEVCapability *virSEVCapabilityPtr; struct _virSEVCapability { @@ -191,6 +198,7 @@ struct _virDomainCaps { virDomainCapsFeatureGIC gic; virSEVCapabilityPtr sev; + virSGXCapabilityPtr sgx; /* add new domain features here */ virTristateBool features[VIR_DOMAIN_CAPS_FEATURE_LAST]; @@ -239,4 +247,9 @@ int virDomainCapsDeviceDefValidate(const virDomainCaps *caps, void virSEVCapabilitiesFree(virSEVCapability *capabilities); +void +virSGXCapabilitiesFree(virSGXCapability *capabilities); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSEVCapability, virSEVCapabilitiesFree); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 01c2e710cd..7b464f9592 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -215,6 +215,7 @@ virDomainCapsEnumSet; virDomainCapsFormat; virDomainCapsNew; virSEVCapabilitiesFree; +virSGXCapabilitiesFree; # conf/domain_conf.h diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ff6ba8c9e9..e2103c7975 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -597,6 +597,9 @@ VIR_ENUM_IMPL(virQEMUCaps, "spapr-tpm-proxy", "numa.hmat", "blockdev-hostdev-scsi", + + /* 380 */ + "sgx-epc", ); @@ -698,11 +701,14 @@ struct _virQEMUCaps { virSEVCapability *sevCapabilities; + virSGXCapability *sgxCapabilities; + /* Capabilities which may differ depending on the accelerator. */ virQEMUCapsAccel kvm; virQEMUCapsAccel tcg; }; + struct virQEMUCapsSearchData { virArch arch; const char *binaryFilter; @@ -1323,6 +1329,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "tcg-accel", QEMU_CAPS_TCG }, { "pvscsi", QEMU_CAPS_SCSI_PVSCSI }, { "spapr-tpm-proxy", QEMU_CAPS_DEVICE_SPAPR_TPM_PROXY }, + { "sgx-epc", QEMU_CAPS_SGX_EPC }, }; @@ -1870,6 +1877,20 @@ virQEMUCapsSEVInfoCopy(virSEVCapabilityPtr *dst, } +static int +virQEMUCapsSGXInfoCopy(virSGXCapabilityPtr *dst, + virSGXCapabilityPtr src) +{ + virSGXCapability *tmp = g_new0(virSGXCapability, 1); + + tmp->flc = src->flc; + tmp->epc_size = src->epc_size; + + *dst = tmp; + return 0; +} + + static void virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccelPtr dst, virQEMUCapsAccelPtr src) @@ -1947,6 +1968,11 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) qemuCaps->sevCapabilities) < 0) goto error; + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC) && + virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities, + qemuCaps->sgxCapabilities) < 0) + goto error; + return ret; error: @@ -1987,6 +2013,7 @@ void virQEMUCapsDispose(void *obj) VIR_FREE(qemuCaps->gicCapabilities); virSEVCapabilitiesFree(qemuCaps->sevCapabilities); + virSGXCapabilitiesFree(qemuCaps->sgxCapabilities); virQEMUCapsAccelClear(&qemuCaps->kvm); virQEMUCapsAccelClear(&qemuCaps->tcg); @@ -2581,6 +2608,13 @@ virQEMUCapsGetSEVCapabilities(virQEMUCapsPtr qemuCaps) } +virSGXCapabilityPtr +virQEMUCapsGetSGXCapabilities(virQEMUCapsPtr qemuCaps) +{ + return qemuCaps->sgxCapabilities; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon) @@ -3405,6 +3439,31 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCapsPtr qemuCaps, } +static int +virQEMUCapsProbeQMPSGXCapabilities(virQEMUCapsPtr qemuCaps, + qemuMonitorPtr mon) +{ + int rc = -1; + virSGXCapability *caps = NULL; + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC)) + return 0; + + if ((rc = qemuMonitorGetSGXCapabilities(mon, &caps)) < 0) + return -1; + + /* SGX isn't actually supported */ + if (rc == 0) { + virQEMUCapsClear(qemuCaps, QEMU_CAPS_SGX_EPC); + return 0; + } + + virSGXCapabilitiesFree(qemuCaps->sgxCapabilities); + qemuCaps->sgxCapabilities = caps; + return 0; +} + + /* * Filter for features which should never be passed to QEMU. Either because * QEMU never supported them or they were dropped as they never did anything @@ -4187,6 +4246,39 @@ virQEMUCapsParseSEVInfo(virQEMUCapsPtr qemuCaps, xmlXPathContextPtr ctxt) return 0; } +static int +virQEMUCapsParseSGXInfo(virQEMUCapsPtr qemuCaps, xmlXPathContextPtr ctxt) +{ + virSGXCapability *sgx = g_new0(virSGXCapability, 1); + + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC)) + return 0; + + if (virXPathBoolean("boolean(./sgx)", ctxt) == 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing SGX platform data in QEMU " + "capabilities cache")); + return -1; + } + + if (virXPathBoolean("boolean(./sgx/flc)", ctxt) == 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing SGX platform flc data in QEMU " + "capabilities cache")); + return -1; + } + + if (virXPathULongLong("string(./sgx/epc_size)", ctxt, &sgx->epc_size) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or malformed SGX platform epc_size information " + "in QEMU capabilities cache")); + return -1; + } + + qemuCaps->sgxCapabilities = g_steal_pointer(&sgx); + return 0; +} + /* * Parsing a doc that looks like @@ -4425,6 +4517,9 @@ virQEMUCapsLoadCache(virArch hostArch, if (virQEMUCapsParseSEVInfo(qemuCaps, ctxt) < 0) goto cleanup; + if (virQEMUCapsParseSGXInfo(qemuCaps, ctxt) < 0) + goto cleanup; + virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); @@ -4601,6 +4696,19 @@ virQEMUCapsFormatSEVInfo(virQEMUCapsPtr qemuCaps, virBufferPtr buf) virBufferAddLit(buf, "</sev>\n"); } +static void +virQEMUCapsFormatSGXInfo(virQEMUCapsPtr qemuCaps, virBufferPtr buf) +{ + virSGXCapabilityPtr sgx = virQEMUCapsGetSGXCapabilities(qemuCaps); + + virBufferAddLit(buf, "<sgx>\n"); + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<flc>%s</flc>\n", sgx->flc ? "yes" : "no"); + virBufferAsprintf(buf, "<epc_size>%llu</epc_size>\n", sgx->epc_size); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</sgx>\n"); +} + char * virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps) @@ -4671,6 +4779,9 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps) if (qemuCaps->sevCapabilities) virQEMUCapsFormatSEVInfo(qemuCaps, &buf); + if (qemuCaps->sgxCapabilities) + virQEMUCapsFormatSGXInfo(qemuCaps, &buf); + if (qemuCaps->kvmSupportsNesting) virBufferAddLit(&buf, "<kvmSupportsNesting/>\n"); @@ -5323,6 +5434,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps, return -1; if (virQEMUCapsProbeQMPSEVCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) + return -1; virQEMUCapsInitProcessCaps(qemuCaps); @@ -6245,6 +6358,31 @@ virQEMUCapsFillDomainFeatureGICCaps(virQEMUCapsPtr qemuCaps, } +/** + * virQEMUCapsFillDomainFeatureiSGXCaps: + * @qemuCaps: QEMU capabilities + * @domCaps: domain capabilities + * + * Take the information about SGX capabilities that has been obtained + * using the 'query-sgx-capabilities' QMP command and stored in @qemuCaps + * and convert it to a form suitable for @domCaps. + */ +static void +virQEMUCapsFillDomainFeatureSGXCaps(virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps) +{ + virSGXCapability *cap = qemuCaps->sgxCapabilities; + + if (!cap) + return; + + domCaps->sgx = g_new0(virSGXCapability, 1); + + domCaps->sgx->flc = cap->flc; + domCaps->sgx->epc_size = cap->epc_size; +} + + /** * virQEMUCapsFillDomainFeatureSEVCaps: * @qemuCaps: QEMU capabilities @@ -6316,6 +6454,7 @@ virQEMUCapsFillDomainCaps(virQEMUCapsPtr qemuCaps, virQEMUCapsFillDomainDeviceRNGCaps(qemuCaps, rng); virQEMUCapsFillDomainFeatureGICCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureSEVCaps(qemuCaps, domCaps); + virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps); return 0; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 5d08941538..0e3af622a7 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -578,6 +578,9 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_NUMA_HMAT, /* -numa hmat */ QEMU_CAPS_BLOCKDEV_HOSTDEV_SCSI, /* -blockdev used for (i)SCSI hostdevs */ + /* 380 */ + QEMU_CAPS_SGX_EPC, /* -object sgx-epc,... */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -759,5 +762,8 @@ virQEMUCapsCPUFeatureFromQEMU(virQEMUCapsPtr qemuCaps, virSEVCapabilityPtr virQEMUCapsGetSEVCapabilities(virQEMUCapsPtr qemuCaps); +virSGXCapabilityPtr +virQEMUCapsGetSGXCapabilities(virQEMUCapsPtr qemuCaps); + virArch virQEMUCapsArchFromString(const char *arch); const char *virQEMUCapsArchToString(virArch arch); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 637361d24d..1e377ee8dc 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3870,6 +3870,16 @@ qemuMonitorGetSEVCapabilities(qemuMonitorPtr mon, } +int +qemuMonitorGetSGXCapabilities(qemuMonitorPtr mon, + virSGXCapability **capabilities) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetSGXCapabilities(mon, capabilities); +} + + int qemuMonitorNBDServerStart(qemuMonitorPtr mon, const virStorageNetHostDef *server, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d20a15c202..76b3cd54c7 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -836,6 +836,9 @@ int qemuMonitorGetGICCapabilities(qemuMonitorPtr mon, int qemuMonitorGetSEVCapabilities(qemuMonitorPtr mon, virSEVCapability **capabilities); +int qemuMonitorGetSGXCapabilities(qemuMonitorPtr mon, + virSGXCapability **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 9cdf6c0f7f..69a6a31aee 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -44,6 +44,7 @@ # include "libvirt_qemu_probes.h" #endif +#define KB 1024 #define VIR_FROM_THIS VIR_FROM_QEMU VIR_LOG_INIT("qemu.qemu_monitor_json"); @@ -7056,6 +7057,92 @@ qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon, } +/** + * qemuMonitorJSONGetSGXCapabilities: + * @mon: qemu monitor object + * @capabilities: pointer to pointer to a SGX capability structure to be filled + * + * This function queries and fills in INTEL's SGX platform-specific data. + * Note that from QEMU's POV both -object sgx-epc and query-sgx-capabilities + * can be present even if SGX is not available, which basically leaves us with + * checking for JSON "GenericError" in order to differentiate between compiled-in + * support and actual SGX support on the platform. + * + * Returns -1 on error, 0 if SGX is not supported, and 1 if SGX is supported on + * the platform. + */ +int +qemuMonitorJSONGetSGXCapabilities(qemuMonitorPtr mon, + virSGXCapability **capabilities) +{ + int ret = -1; + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + virJSONValuePtr caps; + bool sgx = false; + bool flc = false; + unsigned long long section_size = 0; + g_autoptr(virSGXCapability) capability = NULL; + + *capabilities = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-sgx-capabilities", NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return ret; + + /* QEMU has only compiled-in support of SGX */ + if (qemuMonitorJSONHasError(reply, "GenericError")) { + ret = 0; + return ret; + } + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return ret; + + caps = virJSONValueObjectGetObject(reply, "return"); + + if (virJSONValueObjectGetBoolean(caps, "sgx", &sgx) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx reply was missing" + " 'sgx' field")); + return ret; + } + if (!sgx) { + VIR_WARN("sgx is not support %d\n", sgx); + ret = 0; + return ret; + } + + if (virJSONValueObjectGetBoolean(caps, "flc", &flc) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing" + " 'flc' field")); + return ret; + } + + if (virJSONValueObjectGetNumberUlong(caps, "section-size", §ion_size) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing" + " 'section-size' field")); + return ret; + } + + + if (VIR_ALLOC(capability) < 0) + return ret; + + capability->flc = flc; + + capability->epc_size = section_size/(KB); + *capabilities = g_steal_pointer(&capability); + ret = 1; + + return ret; +} + + /** * qemuMonitorJSONGetSEVCapabilities: * @mon: qemu monitor object diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 098ab857be..b0c23e57ac 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -159,6 +159,9 @@ int qemuMonitorJSONGetGICCapabilities(qemuMonitorPtr mon, int qemuMonitorJSONGetSEVCapabilities(qemuMonitorPtr mon, virSEVCapability **capabilities); +int qemuMonitorJSONGetSGXCapabilities(qemuMonitorPtr mon, + virSGXCapability **capabilities); + int qemuMonitorJSONMigrate(qemuMonitorPtr mon, unsigned int flags, const char *uri); -- 2.17.1