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 | 230 ++++++++++++++++++ src/qemu/qemu_capabilities.h | 4 + .../caps_6.2.0.x86_64.replies | 30 ++- .../caps_6.2.0.x86_64.xml | 7 + .../caps_7.0.0.x86_64.replies | 34 ++- .../caps_7.0.0.x86_64.xml | 11 + .../caps_7.1.0.x86_64.replies | 34 ++- .../caps_7.1.0.x86_64.xml | 11 + 8 files changed, 346 insertions(+), 15 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2c3be3ecec..57b5acb150 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -671,6 +671,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "chardev.qemu-vdagent", /* QEMU_CAPS_CHARDEV_QEMU_VDAGENT */ "display-dbus", /* QEMU_CAPS_DISPLAY_DBUS */ "iothread.thread-pool-max", /* QEMU_CAPS_IOTHREAD_THREAD_POOL_MAX */ + "sgx-epc", /* QEMU_CAPS_SGX_EPC */ ); @@ -752,6 +753,8 @@ struct _virQEMUCaps { virSEVCapability *sevCapabilities; + virSGXCapability *sgxCapabilities; + /* Capabilities which may differ depending on the accelerator. */ virQEMUCapsAccel kvm; virQEMUCapsAccel hvf; @@ -1394,6 +1397,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 }, }; @@ -1972,6 +1976,32 @@ virQEMUCapsSEVInfoCopy(virSEVCapability **dst, } +static int +virQEMUCapsSGXInfoCopy(virSGXCapability **dst, + virSGXCapability *src) +{ + g_autoptr(virSGXCapability) tmp = NULL; + + 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->nSections == 0) { + tmp->nSections = 0; + tmp->pSections = NULL; + } else { + tmp->nSections = src->nSections; + tmp->pSections = src->pSections; + } + + *dst = g_steal_pointer(&tmp); + return 0; +} + + static void virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst, virQEMUCapsAccel *src) @@ -2053,6 +2083,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); } @@ -2091,6 +2127,7 @@ void virQEMUCapsDispose(void *obj) virCPUDataFree(qemuCaps->cpuData); virSEVCapabilitiesFree(qemuCaps->sevCapabilities); + virSGXCapabilitiesFree(qemuCaps->sgxCapabilities); virQEMUCapsAccelClear(&qemuCaps->kvm); virQEMUCapsAccelClear(&qemuCaps->hvf); @@ -2616,6 +2653,13 @@ virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps) } +virSGXCapabilityPtr +virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps) +{ + return qemuCaps->sgxCapabilities; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCaps *qemuCaps, qemuMonitor *mon) @@ -3442,6 +3486,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 @@ -4220,6 +4289,116 @@ virQEMUCapsParseSEVInfo(virQEMUCaps *qemuCaps, xmlXPathContextPtr ctxt) } +static int +virQEMUCapsParseSGXInfo(virQEMUCaps *qemuCaps, + xmlXPathContextPtr ctxt) +{ + g_autoptr(virSGXCapability) sgx = NULL; + xmlNodePtr node; + + g_autofree xmlNodePtr *nodes = NULL; + g_autofree xmlNodePtr *sectionNodes = NULL; + g_autofree char *flc = NULL; + g_autofree char *sgx1 = NULL; + g_autofree char *sgx2 = NULL; + + int n = 0; + int nsections = 0; + + 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 ((n = virXPathNodeSet("./sgx/sections", ctxt, &nodes)) < 0) { + sgx->nSections = 0; + sgx->pSections = NULL; + VIR_INFO("Sections was not obtained, so QEMU version is 6.2.0"); + qemuCaps->sgxCapabilities = g_steal_pointer(&sgx); + return 0; + } + + if (n == 0) { + qemuCaps->sgxCapabilities = g_steal_pointer(&sgx); + return 0; + } + + // Got the section, the QEMU version is above 7.0.0 + node = ctxt->node; + ctxt->node = nodes[0]; + nsections = virXPathNodeSet("./section", ctxt, §ionNodes); + ctxt->node = node; + + if (nsections < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse CPU blockers in QEMU capabilities")); + return -1; + } + + if (nsections > 0) { + size_t i; + g_autofree char * strNode = NULL; + g_autofree char * strSize = NULL; + sgx->nSections = nsections; + sgx->pSections = g_new0(virSection, nsections + 1); + + for (i = 0; i < nsections; i++) { + if ((strNode = virXMLPropString(sectionNodes[i], "node")) && + (virStrToLong_ui(strNode, NULL, 10, &(sgx->pSections[i].node)) < 0)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing node name in QEMU " + "capabilities cache")); + return -1; + } + + if ((strSize = virXMLPropString(sectionNodes[i], "size")) && + (virStrToLong_ull(strSize, NULL, 10, &(sgx->pSections[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) { @@ -4522,6 +4701,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)) @@ -4707,6 +4889,49 @@ virQEMUCapsFormatSEVInfo(virQEMUCaps *qemuCaps, virBuffer *buf) } +static void +virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps, + virBuffer *buf) +{ + virSGXCapabilityPtr sgx = virQEMUCapsGetSGXCapabilities(qemuCaps); + size_t i; + + virBufferAddLit(buf, "<sgx supported='yes'>\n"); + virBufferAdjustIndent(buf, 2); + if (sgx->flc) { + virBufferAsprintf(buf, "<flc>%s</flc>\n", "yes"); + } else { + virBufferAsprintf(buf, "<flc>%s</flc>\n", "no"); + } + if (sgx->sgx1) { + virBufferAsprintf(buf, "<sgx1>%s</sgx1>\n", "yes"); + } else { + virBufferAsprintf(buf, "<sgx1>%s</sgx1>\n", "no"); + } + if (sgx->sgx2) { + virBufferAsprintf(buf, "<sgx2>%s</sgx2>\n", "yes"); + } else { + virBufferAsprintf(buf, "<sgx2>%s</sgx2>\n", "no"); + } + virBufferAsprintf(buf, "<section_size unit='KiB'>%llu</section_size>\n", sgx->section_size); + + if (sgx->nSections > 0) { + virBufferAddLit(buf, "<sections>\n"); + + for (i = 0; i < sgx->nSections; i++) { + virBufferAdjustIndent(buf, 2); + virBufferAsprintf(buf, "<section node='%u' ", sgx->pSections[i].node); + virBufferAsprintf(buf, "size='%llu'/>\n", sgx->pSections[i].size); + virBufferAdjustIndent(buf, -2); + } + virBufferAddLit(buf, "</sections>\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</sgx>\n"); +} + + char * virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) { @@ -4788,6 +5013,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) if (qemuCaps->sevCapabilities) virQEMUCapsFormatSEVInfo(qemuCaps, &buf); + if (qemuCaps->sgxCapabilities) + virQEMUCapsFormatSGXInfo(qemuCaps, &buf); + if (qemuCaps->kvmSupportsNesting) virBufferAddLit(&buf, "<kvmSupportsNesting/>\n"); @@ -5455,6 +5683,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 6f35ba1485..fc8c0fde1b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -650,6 +650,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_CHARDEV_QEMU_VDAGENT, /* -chardev qemu-vdagent */ QEMU_CAPS_DISPLAY_DBUS, /* -display dbus */ QEMU_CAPS_IOTHREAD_THREAD_POOL_MAX, /* -object iothread.thread-pool-max */ + QEMU_CAPS_SGX_EPC, /* -object sgx-epc,... */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; @@ -843,6 +844,9 @@ virQEMUCapsCPUFeatureFromQEMU(virQEMUCaps *qemuCaps, virSEVCapability * virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps); +virSGXCapabilityPtr +virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps); + bool virQEMUCapsGetKVMSupportsSecureGuest(virQEMUCaps *qemuCaps) G_GNUC_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..0151ab07fa 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,22 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-51" +} + +{ + "return": { + "sgx": true, + "flc": false, + "sgx1": true, + "sgx2": false, + "section-size": 2048 + }, + "id": "libvirt-51" +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -32715,7 +32731,7 @@ "name": "host" } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33048,7 +33064,7 @@ } } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -33062,7 +33078,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { @@ -33395,7 +33411,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { diff --git a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml index 19605d93ae..e1f177281f 100644 --- a/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.2.0.x86_64.xml @@ -238,6 +238,7 @@ <flag name='virtio-iommu-pci'/> <flag name='virtio-net.rss'/> <flag name='chardev.qemu-vdagent'/> + <flag name='sgx-epc'/> <version>6002000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> @@ -3706,4 +3707,10 @@ <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'>2</section_size> + </sgx> </qemuCaps> diff --git a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.replies index 620442704a..9f806412f7 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": 2048, + "sections": [ + { + "node": 0, + "size": 1024 + }, + { + "node": 1, + "size": 1024 + } + ] + }, + "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 05f844fd5b..7cad1fd7d8 100644 --- a/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.0.0.x86_64.xml @@ -243,6 +243,7 @@ <flag name='virtio-net.rss'/> <flag name='chardev.qemu-vdagent'/> <flag name='display-dbus'/> + <flag name='sgx-epc'/> <version>7000000</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100243</microcodeVersion> @@ -3771,4 +3772,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'>2</section_size> + <sections> + <section node='0' size='1'/> + <section node='1' size='1'/> + </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 025d2db895..b9f9201ac7 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.replies @@ -33866,6 +33866,32 @@ } } +{ + "execute": "query-sgx-capabilities", + "id": "libvirt-51" +} + +{ + "return": { + "sgx": true, + "flc": false, + "sgx1": true, + "sgx2": false, + "section-size": 2048, + "sections": [ + { + "node": 0, + "size": 1024 + }, + { + "node": 1, + "size": 1024 + } + ] + }, + "id": "libvirt-51" +} + { "execute": "query-cpu-model-expansion", "arguments": { @@ -33874,7 +33900,7 @@ "name": "host" } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -34212,7 +34238,7 @@ } } }, - "id": "libvirt-51" + "id": "libvirt-52" } { @@ -34226,7 +34252,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { @@ -34564,7 +34590,7 @@ } } }, - "id": "libvirt-52" + "id": "libvirt-53" } { diff --git a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml index 3707d9b7c9..21b5e361b1 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml @@ -244,6 +244,7 @@ <flag name='chardev.qemu-vdagent'/> <flag name='display-dbus'/> <flag name='iothread.thread-pool-max'/> + <flag name='sgx-epc'/> <version>7000050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> @@ -3569,4 +3570,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'>2</section_size> + <sections> + <section node='0' size='1'/> + <section node='1' size='1'/> + </sections> + </sgx> </qemuCaps> -- 2.25.1