From: Haibin Huang <haibin.huang@xxxxxxxxx> the QMP capabilities: {"return": { "sgx": true, "section-size": 1024, "flc": true } } the domain capabilities: <sgx> <flc>yes</flc> <epc_size>1</epc_size> </sgx> Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> Signed-off-by: Haibin Huang <haibin.huang@xxxxxxxxx> --- src/qemu/qemu_capabilities.c | 203 ++++++++++++++++++ src/qemu/qemu_capabilities.h | 6 + .../caps_6.2.0.x86_64.replies | 27 ++- .../caps_7.0.0.x86_64.replies | 34 ++- .../caps_7.0.0.x86_64.xml | 10 + .../caps_7.1.0.x86_64.replies | 21 +- 6 files changed, 286 insertions(+), 15 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 4fca774425..e0fe1521c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -673,6 +673,9 @@ VIR_ENUM_IMPL(virQEMUCaps, "iothread.thread-pool-max", /* QEMU_CAPS_IOTHREAD_THREAD_POOL_MAX */ "usb-host.guest-resets-all", /* QEMU_CAPS_USB_HOST_GUESTS_RESETS_ALL */ "migration.blocked-reasons", /* QEMU_CAPS_MIGRATION_BLOCKED_REASONS */ + + /* 435 */ + "sgx-epc", /* QEMU_CAPS_SGX_EPC */ ); @@ -754,6 +757,8 @@ struct _virQEMUCaps { virSEVCapability *sevCapabilities; + virSGXCapability *sgxCapabilities; + /* Capabilities which may differ depending on the accelerator. */ virQEMUCapsAccel kvm; virQEMUCapsAccel hvf; @@ -1391,6 +1396,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "s390-pv-guest", QEMU_CAPS_S390_PV_GUEST }, { "virtio-mem-pci", QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI }, { "virtio-iommu-pci", QEMU_CAPS_DEVICE_VIRTIO_IOMMU_PCI }, + { "sgx-epc", QEMU_CAPS_SGX_EPC }, }; @@ -1957,6 +1963,38 @@ virQEMUCapsSEVInfoCopy(virSEVCapability **dst, } +static int +virQEMUCapsSGXInfoCopy(virSGXCapability **dst, + virSGXCapability *src) +{ + g_autoptr(virSGXCapability) tmp = NULL; + + if (!src) { + *dst = NULL; + return 0; + } + + tmp = g_new0(virSGXCapability, 1); + + tmp->flc = src->flc; + tmp->sgx1 = src->sgx1; + tmp->sgx2 = src->sgx2; + + if (src->nSgxSections > 0) { + tmp->sgxSections = g_new0(virSGXSection, src->nSgxSections); + memcpy(tmp->sgxSections, src->sgxSections, + src->nSgxSections * sizeof(*tmp->sgxSections)); + tmp->nSgxSections = src->nSgxSections; + } else { + *dst = NULL; + return 0; + } + + *dst = g_steal_pointer(&tmp); + return 0; +} + + static void virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst, virQEMUCapsAccel *src) @@ -2038,6 +2076,11 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps) qemuCaps->sevCapabilities) < 0) return NULL; + + if (virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities, + qemuCaps->sgxCapabilities) < 0) + return NULL; + return g_steal_pointer(&ret); } @@ -2076,6 +2119,7 @@ void virQEMUCapsDispose(void *obj) virCPUDataFree(qemuCaps->cpuData); virSEVCapabilitiesFree(qemuCaps->sevCapabilities); + virSGXCapabilitiesFree(qemuCaps->sgxCapabilities); virQEMUCapsAccelClear(&qemuCaps->kvm); virQEMUCapsAccelClear(&qemuCaps->hvf); @@ -2601,6 +2645,13 @@ virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps) } +virSGXCapability * +virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps) +{ + return qemuCaps->sgxCapabilities; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -3426,6 +3477,31 @@ virQEMUCapsProbeQMPSEVCapabilities(virQEMUCaps *qemuCaps, } +static int +virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps, + qemuMonitor *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 @@ -4204,6 +4280,90 @@ virQEMUCapsParseSEVInfo(virQEMUCaps *qemuCaps, xmlXPathContextPtr ctxt) } +static int +virQEMUCapsParseSGXInfo(virQEMUCaps *qemuCaps, + xmlXPathContextPtr ctxt) +{ + g_autoptr(virSGXCapability) sgx = NULL; + xmlNodePtr sgxSections = NULL; + g_autofree char *flc = NULL; + g_autofree char *sgx1 = NULL; + g_autofree char *sgx2 = NULL; + + 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; + } + + sgx = g_new0(virSGXCapability, 1); + + if ((!(flc = virXPathString("string(./sgx/flc)", ctxt))) || + virStringParseYesNo(flc, &sgx->flc) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid SGX platform flc in QEMU capabilities cache")); + return -1; + } + + if ((!(sgx1 = virXPathString("string(./sgx/sgx1)", ctxt))) || + virStringParseYesNo(sgx1, &sgx->sgx1) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid SGX platform sgx1 in QEMU capabilities cache")); + return -1; + } + + if ((!(sgx2 = virXPathString("string(./sgx/sgx2)", ctxt))) || + virStringParseYesNo(sgx2, &sgx->sgx2) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or invalid SGX platform sgx2 in QEMU capabilities cache")); + return -1; + } + + if ((sgxSections = virXPathNode("./sgx/sections", ctxt))) { + g_autofree xmlNodePtr *sectionNodes = NULL; + int nSgxSections = 0; + size_t i; + VIR_XPATH_NODE_AUTORESTORE(ctxt); + + ctxt->node = sgxSections; + nSgxSections = virXPathNodeSet("./section", ctxt, §ionNodes); + + if (nSgxSections < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse SGX sections in QEMU capabilities cache")); + return -1; + } + + sgx->nSgxSections = nSgxSections; + sgx->sgxSections = g_new0(virSGXSection, nSgxSections); + + for (i = 0; i < nSgxSections; i++) { + if (virXMLPropUInt(sectionNodes[i], "node", 10, + VIR_XML_PROP_REQUIRED, + &(sgx->sgxSections[i].node)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing node name in QEMU capabilities cache")); + return -1; + } + + if (virXMLPropULongLong(sectionNodes[i], "size", 10, + VIR_XML_PROP_REQUIRED, + &(sgx->sgxSections[i].size)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing size name in QEMU capabilities cache")); + return -1; + } + } + } + + qemuCaps->sgxCapabilities = g_steal_pointer(&sgx); + return 0; +} + + static int virQEMUCapsParseFlags(virQEMUCaps *qemuCaps, xmlXPathContextPtr ctxt) { @@ -4506,6 +4666,9 @@ virQEMUCapsLoadCache(virArch hostArch, if (virQEMUCapsParseSEVInfo(qemuCaps, ctxt) < 0) return -1; + if (virQEMUCapsParseSGXInfo(qemuCaps, ctxt) < 0) + return -1; + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) @@ -4691,6 +4854,41 @@ virQEMUCapsFormatSEVInfo(virQEMUCaps *qemuCaps, virBuffer *buf) } +static void +virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps, + virBuffer *buf) +{ + virSGXCapability *sgx = virQEMUCapsGetSGXCapabilities(qemuCaps); + if (sgx == NULL) { + virBufferAddLit(buf, "<sgx supported='no'/>\n"); + return; + } + + virBufferAddLit(buf, "<sgx supported='yes'>\n"); + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<flc>%s</flc>\n", sgx->flc ? "yes" : "no"); + virBufferAsprintf(buf, "<sgx1>%s</sgx1>\n", sgx->sgx1 ? "yes" : "no"); + virBufferAsprintf(buf, "<sgx2>%s</sgx2>\n", sgx->sgx2 ? "yes" : "no"); + + if (sgx->nSgxSections > 0) { + size_t i; + virBufferAddLit(buf, "<sections>\n"); + + for (i = 0; i < sgx->nSgxSections; i++) { + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<section node='%u' ", sgx->sgxSections[i].node); + virBufferAsprintf(buf, "size='%llu' ", sgx->sgxSections[i].size); + virBufferAddLit(buf, "unit='KiB'/>\n"); + virBufferAdjustIndent(buf, -2); + } + virBufferAddLit(buf, "</sections>\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</sgx>\n"); +} + + char * virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) { @@ -4772,6 +4970,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) if (qemuCaps->sevCapabilities) virQEMUCapsFormatSEVInfo(qemuCaps, &buf); + if (qemuCaps->sgxCapabilities) + virQEMUCapsFormatSGXInfo(qemuCaps, &buf); + if (qemuCaps->kvmSupportsNesting) virBufferAddLit(&buf, "<kvmSupportsNesting/>\n"); @@ -5425,6 +5626,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, return -1; if (virQEMUCapsProbeQMPSEVCapabilities(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0) + return -1; virQEMUCapsInitProcessCaps(qemuCaps); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index fc8bb6e2ab..4d502847f3 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -653,6 +653,9 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_USB_HOST_GUESTS_RESETS_ALL, /* -device usb-host.guest-resets-all */ QEMU_CAPS_MIGRATION_BLOCKED_REASONS, /* query-migrate returns 'blocked-reasons */ + /* 435 */ + QEMU_CAPS_SGX_EPC, /* -object sgx-epc,... */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -845,6 +848,9 @@ virQEMUCapsCPUFeatureFromQEMU(virQEMUCaps *qemuCaps, virSEVCapability * virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps); +virSGXCapability * +virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps); + bool virQEMUCapsGetKVMSupportsSecureGuest(virQEMUCaps *qemuCaps) G_NO_INLINE; diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies index e235532d62..7866f7741b 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies @@ -7459,15 +7459,15 @@ "type": "bool" }, { - "name": "sgx1", + "name": "flc", "type": "bool" }, { - "name": "sgx2", + "name": "sgx1", "type": "bool" }, { - "name": "flc", + "name": "sgx2", "type": "bool" }, { @@ -32707,6 +32707,19 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-51" +} + +{ + "id": "libvirt-51", + "error": { + "class": "GenericError", + "desc": "SGX is not enabled in KVM" + } +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -32715,7 +32728,7 @@ "name": "host" } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33048,7 +33061,7 @@ } } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33062,7 +33075,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { @@ -33395,7 +33408,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies index 620442704a..e06af7d797 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies @@ -33317,6 +33317,32 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-51" +} + +{ + "return": { + "sgx": true, + "flc": false, + "sgx1": true, + "sgx2": false, + "section-size": 536870912, + "sections": [ + { + "node": 0, + "size": 268435456 + }, + { + "node": 1, + "size": 268435456 + } + ] + }, + "id": "libvirt-51" +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -33325,7 +33351,7 @@ "name": "host" } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33662,7 +33688,7 @@ } } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33676,7 +33702,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { @@ -34013,7 +34039,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml index 86fe88b878..abc9e83f0c 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml @@ -224,6 +224,7 @@ <flag name='display-dbus'/> <flag name='usb-host.guest-resets-all'/> <flag name='migration.blocked-reasons'/> + <flag name='sgx-epc'/> <version>7000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100243</microcodeVersion> @@ -3752,4 +3753,13 @@ <machine type='tcg' name='pc-q35-2.5' hotplugCpus='yes' maxCpus='255' defaultCPU='qemu64-x86_64-cpu' numaMemSupported='yes' defaultRAMid='pc.ram'/> <machine type='tcg' name='pc-i440fx-3.0' hotplugCpus='yes' maxCpus='255' defaultCPU='qemu64-x86_64-cpu' numaMemSupported='yes' defaultRAMid='pc.ram'/> <machine type='tcg' name='pc-q35-2.11' hotplugCpus='yes' maxCpus='288' defaultCPU='qemu64-x86_64-cpu' numaMemSupported='yes' defaultRAMid='pc.ram'/> + <sgx supported='yes'> + <flc>no</flc> + <sgx1>yes</sgx1> + <sgx2>no</sgx2> + <sections> + <section node='0' size='262144' unit='KiB'/> + <section node='1' size='262144' unit='KiB'/> + </sections> + </sgx> </qemuCaps> diff --git a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies index d893d67ea8..bb6f670ebf 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies @@ -34006,6 +34006,19 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-51" +} + +{ + "id": "libvirt-51", + "error": { + "class": "GenericError", + "desc": "SGX is not enabled in KVM" + } +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -34014,7 +34027,7 @@ "name": "host" } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -34352,7 +34365,7 @@ } } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -34366,7 +34379,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { @@ -34704,7 +34717,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { -- 2.25.1