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 | 204 ++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 + .../caps_6.2.0.x86_64.replies | 21 +- .../caps_7.0.0.x86_64.replies | 34 ++- .../caps_7.0.0.x86_64.xml | 11 + .../caps_7.1.0.x86_64.replies | 21 +- 6 files changed, 283 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 68aefe1d86..dfd00311c2 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -676,6 +676,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 435 */ "query-stats", /* QEMU_CAPS_QUERY_STATS */ + "sgx-epc", /* QEMU_CAPS_SGX_EPC */ ); @@ -757,6 +758,8 @@ struct _virQEMUCaps { virSEVCapability *sevCapabilities; + virSGXCapability *sgxCapabilities; + /* Capabilities which may differ depending on the accelerator. */ virQEMUCapsAccel kvm; virQEMUCapsAccel hvf; @@ -1392,6 +1395,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 }, }; @@ -1917,6 +1921,36 @@ 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; + tmp->section_size = src->section_size; + + 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; + } + + *dst = g_steal_pointer(&tmp); + return 0; +} + + static void virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst, virQEMUCapsAccel *src) @@ -1998,6 +2032,12 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps) qemuCaps->sevCapabilities) < 0) return NULL; + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC) && + virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities, + qemuCaps->sgxCapabilities) < 0) + return NULL; + return g_steal_pointer(&ret); } @@ -2036,6 +2076,7 @@ void virQEMUCapsDispose(void *obj) virCPUDataFree(qemuCaps->cpuData); virSEVCapabilitiesFree(qemuCaps->sevCapabilities); + virSGXCapabilitiesFree(qemuCaps->sgxCapabilities); virQEMUCapsAccelClear(&qemuCaps->kvm); virQEMUCapsAccelClear(&qemuCaps->hvf); @@ -2561,6 +2602,13 @@ virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps) } +virSGXCapability * +virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps) +{ + return qemuCaps->sgxCapabilities; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -3386,6 +3434,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 @@ -4164,6 +4237,97 @@ 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 (virXPathULongLong("string(./sgx/section_size)", ctxt, + &sgx->section_size) < 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing or malformed SGX platform section_size 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) { @@ -4453,6 +4617,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)) @@ -4638,6 +4805,38 @@ virQEMUCapsFormatSEVInfo(virQEMUCaps *qemuCaps, virBuffer *buf) } +static void +virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps, + virBuffer *buf) +{ + virSGXCapability *sgx = virQEMUCapsGetSGXCapabilities(qemuCaps); + + 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"); + virBufferAsprintf(buf, "<section_size unit='KiB'>%llu</section_size>\n", sgx->section_size); + + 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) { @@ -4719,6 +4918,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) if (qemuCaps->sevCapabilities) virQEMUCapsFormatSEVInfo(qemuCaps, &buf); + if (qemuCaps->sgxCapabilities) + virQEMUCapsFormatSGXInfo(qemuCaps, &buf); + if (qemuCaps->kvmSupportsNesting) virBufferAddLit(&buf, "<kvmSupportsNesting/>\n"); @@ -5363,6 +5565,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 ca919ff368..f57e0b40b8 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -655,6 +655,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 435 */ QEMU_CAPS_QUERY_STATS, /* accepts query-stats */ + QEMU_CAPS_SGX_EPC, /* -object sgx-epc,... */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -848,6 +849,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 b4b853eb51..fb32cb7a03 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.replies @@ -32419,6 +32419,19 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-48" +} + +{ + "id": "libvirt-48", + "error": { + "class": "GenericError", + "desc": "SGX is not enabled in KVM" + } +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -32427,7 +32440,7 @@ "name": "host" } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -32760,7 +32773,7 @@ } } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -32774,7 +32787,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { @@ -33107,7 +33120,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies index 0590294255..a331006289 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies @@ -33029,6 +33029,32 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-48" +} + +{ + "return": { + "sgx": true, + "flc": false, + "sgx1": true, + "sgx2": false, + "section-size": 536870912, + "sections": [ + { + "node": 0, + "size": 268435456 + }, + { + "node": 1, + "size": 268435456 + } + ] + }, + "id": "libvirt-48" +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -33037,7 +33063,7 @@ "name": "host" } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -33374,7 +33400,7 @@ } } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -33388,7 +33414,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { @@ -33725,7 +33751,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml index dc7b041294..5da7f0d386 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml @@ -214,6 +214,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> @@ -3742,4 +3743,14 @@ <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> + <section_size unit='KiB'>524288</section_size> + <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 126c76301e..9eb851694f 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies @@ -33722,6 +33722,19 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-48" +} + +{ + "id": "libvirt-48", + "error": { + "class": "GenericError", + "desc": "SGX is not enabled in KVM" + } +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -33730,7 +33743,7 @@ "name": "host" } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -34068,7 +34081,7 @@ } } }, - "id": "libvirt-48" + "id": "libvirt-49" } { @@ -34082,7 +34095,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { @@ -34420,7 +34433,7 @@ } } }, - "id": "libvirt-49" + "id": "libvirt-50" } { -- 2.25.1