[libvirt][PATCH v16 1/9] domain_capabilities: Define SGX capabilities structs

From: Haibin Huang <haibin.huang@intel.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/conf/domain_capabilities.c | 11 +++++++++++ src/conf/domain_capabilities.h | 22 ++++++++++++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 34 insertions(+) diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 653123f293..869b5d68e6 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -76,6 +76,17 @@ virSEVCapabilitiesFree(virSEVCapability *cap) } +void +virSGXCapabilitiesFree(virSGXCapability *cap) +{ + if (!cap) + return; + + g_free(cap->sgxSections); + g_free(cap); +} + + static void virDomainCapsDispose(void *obj) { diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index a526969cda..3c9fd7f7de 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -193,6 +193,22 @@ struct _virSEVCapability { unsigned int max_es_guests; }; +typedef struct _virSGXSection virSGXSection; +struct _virSGXSection { + unsigned long long size; + unsigned int node; +}; + +typedef struct _virSGXCapability virSGXCapability; +struct _virSGXCapability { + bool flc; + bool sgx1; + bool sgx2; + unsigned long long section_size; + size_t nSgxSections; + virSGXSection *sgxSections; +}; + typedef enum { VIR_DOMAIN_CAPS_FEATURE_IOTHREADS = 0, VIR_DOMAIN_CAPS_FEATURE_VMCOREINFO, @@ -229,6 +245,7 @@ struct _virDomainCaps { virDomainCapsFeatureGIC gic; virSEVCapability *sev; + virSGXCapability *sgx; /* add new domain features here */ virTristateBool features[VIR_DOMAIN_CAPS_FEATURE_LAST]; @@ -277,3 +294,8 @@ void virSEVCapabilitiesFree(virSEVCapability *capabilities); G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSEVCapability, virSEVCapabilitiesFree); + +void +virSGXCapabilitiesFree(virSGXCapability *capabilities); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 00cb07709d..97b019d00a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -218,6 +218,7 @@ virDomainCapsEnumSet; virDomainCapsFormat; virDomainCapsNew; virSEVCapabilitiesFree; +virSGXCapabilitiesFree; # conf/domain_conf.h -- 2.25.1

From: Haibin Huang <haibin.huang@intel.com> Generate the QMP command for query-sgx-capabilities and the command return SGX capabilities from QMP. {"execute":"query-sgx-capabilities"} the right reply: {"return": { "sgx": true, "section-size": 197132288, "flc": true } } the error reply: {"error": {"class": "GenericError", "desc": "SGX is not enabled in KVM"} } Signed-off-by: Haibin Huang <haibin.huang@intel.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/qemu/qemu_monitor.c | 10 ++++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 113 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++ 4 files changed, 130 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index c2808c75a3..9068865972 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3418,6 +3418,16 @@ qemuMonitorGetSEVCapabilities(qemuMonitor *mon, } +int +qemuMonitorGetSGXCapabilities(qemuMonitor *mon, + virSGXCapability **capabilities) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetSGXCapabilities(mon, capabilities); +} + + int qemuMonitorNBDServerStart(qemuMonitor *mon, const virStorageNetHostDef *server, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 4d770486be..be65fdcfed 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -824,6 +824,9 @@ int qemuMonitorGetGICCapabilities(qemuMonitor *mon, int qemuMonitorGetSEVCapabilities(qemuMonitor *mon, virSEVCapability **capabilities); +int qemuMonitorGetSGXCapabilities(qemuMonitor *mon, + virSGXCapability **capabilities); + typedef enum { QEMU_MONITOR_MIGRATE_RESUME = 1 << 0, /* resume failed post-copy migration */ QEMU_MONITOR_MIGRATION_FLAGS_LAST diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b63400354b..32e0c2ff17 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -6027,6 +6027,119 @@ qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon, return 1; } + +/** + * 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(qemuMonitor *mon, + virSGXCapability **capabilities) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + g_autoptr(virSGXCapability) capability = NULL; + unsigned long long section_size_sum = 0; + virJSONValue *sgxSections = NULL; + virJSONValue *caps; + size_t i; + + *capabilities = NULL; + capability = g_new0(virSGXCapability, 1); + + if (!(cmd = qemuMonitorJSONMakeCommand("query-sgx-capabilities", NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + /* QEMU has only compiled-in support of SGX */ + if (qemuMonitorJSONHasError(reply, "GenericError")) + return 0; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + caps = virJSONValueObjectGetObject(reply, "return"); + + if (virJSONValueObjectGetBoolean(caps, "flc", &capability->flc) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'flc' field")); + return -1; + } + + if (virJSONValueObjectGetBoolean(caps, "sgx1", &capability->sgx1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'sgx1' field")); + return -1; + } + + if (virJSONValueObjectGetBoolean(caps, "sgx2", &capability->sgx2) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'sgx2' field")); + return -1; + } + + if ((sgxSections = virJSONValueObjectGetArray(caps, "sections"))) { + /* SGX EPC sections info was added since QEMU 7.0.0 */ + unsigned long long size; + + capability->nSgxSections = virJSONValueArraySize(sgxSections); + capability->sgxSections = g_new0(virSGXSection, capability->nSgxSections); + + for (i = 0; i < capability->nSgxSections; i++) { + virJSONValue *elem = virJSONValueArrayGet(sgxSections, i); + + if (virJSONValueObjectGetNumberUlong(elem, "size", &size) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'size' field")); + return -1; + } + capability->sgxSections[i].size = size / 1024; + section_size_sum += capability->sgxSections[i].size; + + if (virJSONValueObjectGetNumberUint(elem, "node", + &capability->sgxSections[i].node) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'node' field")); + return -1; + } + } + } else { + /* no support for QEMU version older than 7.0.0 */ + return 0; + } + + if (virJSONValueObjectHasKey(caps, "section-size")) { + unsigned long long section_size = 0; + + if (virJSONValueObjectGetNumberUlong(caps, "section-size", §ion_size) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-sgx-capabilities reply was missing 'section-size' field")); + return -1; + } + capability->section_size = section_size / 1024; + } else { + /* QEMU no longer reports deprecated attribute. */ + capability->section_size = section_size_sum; + } + + *capabilities = g_steal_pointer(&capability); + return 1; +} + + static virJSONValue * qemuMonitorJSONBuildInetSocketAddress(const char *host, const char *port) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index a53e6423df..09e770f531 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -161,6 +161,10 @@ int qemuMonitorJSONGetGICCapabilities(qemuMonitor *mon, virGICCapability **capabilities); +int +qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon, + virSGXCapability **capabilities); + int qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon, virSEVCapability **capabilities); -- 2.25.1

From: Haibin Huang <haibin.huang@intel.com> 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@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- 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

From: Haibin Huang <haibin.huang@intel.com> Extend hypervisor capabilities to include sgx feature. When available, the hypervisor supports launching an VM with SGX on Intel platfrom. The SGX feature tag privides additional details like section size and sgx1 or sgx2. Signed-off-by: Haibin Huang <haibin.huang@intel.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- docs/formatdomaincaps.rst | 40 +++++++++++++++++ src/conf/domain_capabilities.c | 36 ++++++++++++++++ src/conf/schemas/domaincaps.rng | 43 +++++++++++++++++++ src/qemu/qemu_capabilities.c | 16 +++++++ tests/domaincapsdata/bhyve_basic.x86_64.xml | 1 + tests/domaincapsdata/bhyve_fbuf.x86_64.xml | 1 + tests/domaincapsdata/bhyve_uefi.x86_64.xml | 1 + tests/domaincapsdata/empty.xml | 1 + tests/domaincapsdata/libxl-xenfv.xml | 1 + tests/domaincapsdata/libxl-xenpv.xml | 1 + .../domaincapsdata/qemu_4.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_4.2.0-tcg.x86_64.xml | 1 + .../qemu_4.2.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_4.2.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_4.2.0.ppc64.xml | 1 + tests/domaincapsdata/qemu_4.2.0.s390x.xml | 1 + tests/domaincapsdata/qemu_4.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_5.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_5.0.0-tcg.x86_64.xml | 1 + .../qemu_5.0.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_5.0.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_5.0.0.ppc64.xml | 1 + tests/domaincapsdata/qemu_5.0.0.x86_64.xml | 1 + .../domaincapsdata/qemu_5.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_5.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_5.1.0.sparc.xml | 1 + tests/domaincapsdata/qemu_5.1.0.x86_64.xml | 1 + .../domaincapsdata/qemu_5.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_5.2.0-tcg.x86_64.xml | 1 + .../qemu_5.2.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_5.2.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_5.2.0.ppc64.xml | 1 + tests/domaincapsdata/qemu_5.2.0.s390x.xml | 1 + tests/domaincapsdata/qemu_5.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_6.0.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.0.0-tcg.x86_64.xml | 1 + .../qemu_6.0.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_6.0.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_6.0.0.s390x.xml | 1 + tests/domaincapsdata/qemu_6.0.0.x86_64.xml | 1 + .../domaincapsdata/qemu_6.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_6.1.0.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_6.2.0-tcg.x86_64.xml | 1 + .../qemu_6.2.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.ppc64.xml | 1 + tests/domaincapsdata/qemu_6.2.0.x86_64.xml | 1 + .../domaincapsdata/qemu_7.0.0-q35.x86_64.xml | 10 +++++ .../domaincapsdata/qemu_7.0.0-tcg.x86_64.xml | 10 +++++ .../qemu_7.0.0-virt.aarch64.xml | 1 + tests/domaincapsdata/qemu_7.0.0.aarch64.xml | 1 + tests/domaincapsdata/qemu_7.0.0.ppc64.xml | 1 + tests/domaincapsdata/qemu_7.0.0.x86_64.xml | 10 +++++ .../domaincapsdata/qemu_7.1.0-q35.x86_64.xml | 1 + .../domaincapsdata/qemu_7.1.0-tcg.x86_64.xml | 1 + tests/domaincapsdata/qemu_7.1.0.x86_64.xml | 1 + 58 files changed, 216 insertions(+) diff --git a/docs/formatdomaincaps.rst b/docs/formatdomaincaps.rst index 70f46b972a..26034b1c66 100644 --- a/docs/formatdomaincaps.rst +++ b/docs/formatdomaincaps.rst @@ -554,6 +554,16 @@ capabilities. All features occur as children of the main ``features`` element. <cbitpos>47</cbitpos> <reduced-phys-bits>1</reduced-phys-bits> </sev> + <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> </features> </domainCapabilities> @@ -633,3 +643,33 @@ in domain XML <formatdomain.html#launch-security>`__ ``maxESGuests`` The maximum number of SEV-ES guests that can be launched on the host. This value may be configurable in the firmware for some hosts. + +SGX capabilities +^^^^^^^^^^^^^^^^ + +Intel Software Guard Extensions (Intel SGX) capabilities are exposed under the +``sgx`` element. + +Intel SGX helps protect data in use via unique application isolation technology. +Protect selected code and data from modification using hardened enclaves with +Intel SGX. + +For more details on the SGX feature, please follow resources in the SGX developer's +document store. In order to use SGX with libvirt have a look at `SGX in domain XML +<formatdomain.html#memory-devices>`__ + +``flc`` + FLC (Flexible Launch Control), not strictly part of SGX2, but was not part of + original SGX hardware either. + +``sgx1`` + the sgx version 1. + +``sgx2`` + The sgx version 2. + +``section_size`` + The size of the SGX enclave page cache (called EPC). + +``sections`` + The sections of the SGX enclave page cache (called EPC). diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 869b5d68e6..81d08f7091 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -99,6 +99,7 @@ virDomainCapsDispose(void *obj) virObjectUnref(caps->cpu.custom); virCPUDefFree(caps->cpu.hostModel); virSEVCapabilitiesFree(caps->sev); + virSGXCapabilitiesFree(caps->sgx); values = &caps->os.loader.values; for (i = 0; i < values->nvalues; i++) @@ -621,6 +622,40 @@ virDomainCapsFeatureSEVFormat(virBuffer *buf, virBufferAddLit(buf, "</sev>\n"); } +static void +virDomainCapsFeatureSGXFormat(virBuffer *buf, + const virSGXCapability *sgx) +{ + if (!sgx) { + 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"); + 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='%d' ", 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"); +} static void virDomainCapsFormatFeatures(const virDomainCaps *caps, @@ -641,6 +676,7 @@ virDomainCapsFormatFeatures(const virDomainCaps *caps, } virDomainCapsFeatureSEVFormat(&childBuf, caps->sev); + virDomainCapsFeatureSGXFormat(&childBuf, caps->sgx); virXMLFormatElement(buf, "features", NULL, &childBuf); } diff --git a/src/conf/schemas/domaincaps.rng b/src/conf/schemas/domaincaps.rng index 9cbc2467ab..3dd22c8e28 100644 --- a/src/conf/schemas/domaincaps.rng +++ b/src/conf/schemas/domaincaps.rng @@ -270,6 +270,9 @@ <optional> <ref name="sev"/> </optional> + <optional> + <ref name="sgx"/> + </optional> </element> </define> @@ -330,6 +333,46 @@ </element> </define> + <define name="sgx"> + <element name="sgx"> + <ref name="supported"/> + <optional> + <element name="flc"> + <ref name="virYesNo"/> + </element> + <element name="sgx1"> + <ref name="virYesNo"/> + </element> + <element name="sgx2"> + <ref name="virYesNo"/> + </element> + <element name="section_size"> + <attribute name="unit"> + <value>KiB</value> + </attribute> + <data type="unsignedLong"/> + </element> + <optional> + <element name="sections"> + <zeroOrMore> + <element name="section"> + <attribute name="node"> + <data type="unsignedInt"/> + </attribute> + <attribute name="size"> + <data type="unsignedLong"/> + </attribute> + <attribute name="unit"> + <value>KiB</value> + </attribute> + </element> + </zeroOrMore> + </element> + </optional> + </optional> + </element> + </define> + <define name="value"> <zeroOrMore> <element name="value"> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index dfd00311c2..b32f63cfde 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -6618,6 +6618,21 @@ virQEMUCapsFillDomainFeatureS390PVCaps(virQEMUCaps *qemuCaps, } } +/** + * virQEMUCapsFillDomainFeatureSGXCaps: + * @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(virQEMUCaps *qemuCaps, + virDomainCaps *domCaps) +{ + virQEMUCapsSGXInfoCopy(&domCaps->sgx, qemuCaps->sgxCapabilities); +} int virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, @@ -6670,6 +6685,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps, virQEMUCapsFillDomainFeatureGICCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureSEVCaps(qemuCaps, domCaps); virQEMUCapsFillDomainFeatureS390PVCaps(qemuCaps, domCaps); + virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps); return 0; } diff --git a/tests/domaincapsdata/bhyve_basic.x86_64.xml b/tests/domaincapsdata/bhyve_basic.x86_64.xml index 745f325531..dd054577c0 100644 --- a/tests/domaincapsdata/bhyve_basic.x86_64.xml +++ b/tests/domaincapsdata/bhyve_basic.x86_64.xml @@ -33,5 +33,6 @@ <vmcoreinfo supported='no'/> <genid supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/bhyve_fbuf.x86_64.xml b/tests/domaincapsdata/bhyve_fbuf.x86_64.xml index bb11c02ae9..0b1d9c17d7 100644 --- a/tests/domaincapsdata/bhyve_fbuf.x86_64.xml +++ b/tests/domaincapsdata/bhyve_fbuf.x86_64.xml @@ -50,5 +50,6 @@ <vmcoreinfo supported='no'/> <genid supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/bhyve_uefi.x86_64.xml b/tests/domaincapsdata/bhyve_uefi.x86_64.xml index dfd2360d74..69fff197a7 100644 --- a/tests/domaincapsdata/bhyve_uefi.x86_64.xml +++ b/tests/domaincapsdata/bhyve_uefi.x86_64.xml @@ -42,5 +42,6 @@ <vmcoreinfo supported='no'/> <genid supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/empty.xml b/tests/domaincapsdata/empty.xml index d3e2d89b60..97752ca04a 100644 --- a/tests/domaincapsdata/empty.xml +++ b/tests/domaincapsdata/empty.xml @@ -13,5 +13,6 @@ </devices> <features> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/libxl-xenfv.xml b/tests/domaincapsdata/libxl-xenfv.xml index cc5b3847e2..c71d759517 100644 --- a/tests/domaincapsdata/libxl-xenfv.xml +++ b/tests/domaincapsdata/libxl-xenfv.xml @@ -76,5 +76,6 @@ <vmcoreinfo supported='no'/> <genid supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/libxl-xenpv.xml b/tests/domaincapsdata/libxl-xenpv.xml index 325f1e50b3..8ae2370b7e 100644 --- a/tests/domaincapsdata/libxl-xenpv.xml +++ b/tests/domaincapsdata/libxl-xenpv.xml @@ -66,5 +66,6 @@ <vmcoreinfo supported='no'/> <genid supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml index 0ec4c570ac..0ad10127bc 100644 --- a/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_4.2.0-q35.x86_64.xml @@ -224,5 +224,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_4.2.0-tcg.x86_64.xml index 4e0cb08b72..7c81afd411 100644 --- a/tests/domaincapsdata/qemu_4.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_4.2.0-tcg.x86_64.xml @@ -239,5 +239,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_4.2.0-virt.aarch64.xml index 05d606967b..1a87fc417b 100644 --- a/tests/domaincapsdata/qemu_4.2.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_4.2.0-virt.aarch64.xml @@ -177,5 +177,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0.aarch64.xml b/tests/domaincapsdata/qemu_4.2.0.aarch64.xml index f19ad5e6db..943c3605d8 100644 --- a/tests/domaincapsdata/qemu_4.2.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_4.2.0.aarch64.xml @@ -171,5 +171,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0.ppc64.xml b/tests/domaincapsdata/qemu_4.2.0.ppc64.xml index 8ea7ad5714..2f347aa542 100644 --- a/tests/domaincapsdata/qemu_4.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_4.2.0.ppc64.xml @@ -144,5 +144,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0.s390x.xml b/tests/domaincapsdata/qemu_4.2.0.s390x.xml index fb162ea578..8150e5119a 100644 --- a/tests/domaincapsdata/qemu_4.2.0.s390x.xml +++ b/tests/domaincapsdata/qemu_4.2.0.s390x.xml @@ -247,5 +247,6 @@ <backup supported='no'/> <s390-pv supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_4.2.0.x86_64.xml b/tests/domaincapsdata/qemu_4.2.0.x86_64.xml index d8793bb38a..d55072f6cf 100644 --- a/tests/domaincapsdata/qemu_4.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_4.2.0.x86_64.xml @@ -224,5 +224,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_5.0.0-q35.x86_64.xml index 036e446c64..335c14e643 100644 --- a/tests/domaincapsdata/qemu_5.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.0.0-q35.x86_64.xml @@ -226,5 +226,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_5.0.0-tcg.x86_64.xml index 4df4e86cf1..e5cb80bc4f 100644 --- a/tests/domaincapsdata/qemu_5.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.0.0-tcg.x86_64.xml @@ -241,5 +241,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_5.0.0-virt.aarch64.xml index bb8500baa6..9b67bab7a7 100644 --- a/tests/domaincapsdata/qemu_5.0.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_5.0.0-virt.aarch64.xml @@ -189,5 +189,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0.aarch64.xml b/tests/domaincapsdata/qemu_5.0.0.aarch64.xml index e7227d092f..24ff712b2c 100644 --- a/tests/domaincapsdata/qemu_5.0.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_5.0.0.aarch64.xml @@ -183,5 +183,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0.ppc64.xml b/tests/domaincapsdata/qemu_5.0.0.ppc64.xml index cac329fd08..99d02cb578 100644 --- a/tests/domaincapsdata/qemu_5.0.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_5.0.0.ppc64.xml @@ -150,5 +150,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.0.0.x86_64.xml b/tests/domaincapsdata/qemu_5.0.0.x86_64.xml index e901d12918..f30dd29cb3 100644 --- a/tests/domaincapsdata/qemu_5.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.0.0.x86_64.xml @@ -226,5 +226,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_5.1.0-q35.x86_64.xml index df1572c901..c168522e43 100644 --- a/tests/domaincapsdata/qemu_5.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.1.0-q35.x86_64.xml @@ -227,5 +227,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_5.1.0-tcg.x86_64.xml index 3a6dc7b5fc..63023b608c 100644 --- a/tests/domaincapsdata/qemu_5.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.1.0-tcg.x86_64.xml @@ -241,5 +241,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.1.0.sparc.xml b/tests/domaincapsdata/qemu_5.1.0.sparc.xml index 5c1c0c4680..ae8474a696 100644 --- a/tests/domaincapsdata/qemu_5.1.0.sparc.xml +++ b/tests/domaincapsdata/qemu_5.1.0.sparc.xml @@ -113,5 +113,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.1.0.x86_64.xml b/tests/domaincapsdata/qemu_5.1.0.x86_64.xml index e0e8e0ed12..b57e846c96 100644 --- a/tests/domaincapsdata/qemu_5.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.1.0.x86_64.xml @@ -227,5 +227,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_5.2.0-q35.x86_64.xml index 6a49f568be..e94668a9e6 100644 --- a/tests/domaincapsdata/qemu_5.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.2.0-q35.x86_64.xml @@ -227,5 +227,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_5.2.0-tcg.x86_64.xml index f41f47c346..3b3cee8899 100644 --- a/tests/domaincapsdata/qemu_5.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.2.0-tcg.x86_64.xml @@ -241,5 +241,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_5.2.0-virt.aarch64.xml index dfd792c031..2fe1bf3a89 100644 --- a/tests/domaincapsdata/qemu_5.2.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_5.2.0-virt.aarch64.xml @@ -189,5 +189,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0.aarch64.xml b/tests/domaincapsdata/qemu_5.2.0.aarch64.xml index e7227d092f..24ff712b2c 100644 --- a/tests/domaincapsdata/qemu_5.2.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_5.2.0.aarch64.xml @@ -183,5 +183,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0.ppc64.xml b/tests/domaincapsdata/qemu_5.2.0.ppc64.xml index 88e4837ec3..724bb899dc 100644 --- a/tests/domaincapsdata/qemu_5.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_5.2.0.ppc64.xml @@ -150,5 +150,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0.s390x.xml b/tests/domaincapsdata/qemu_5.2.0.s390x.xml index 2a2ca8abcf..496c08dd34 100644 --- a/tests/domaincapsdata/qemu_5.2.0.s390x.xml +++ b/tests/domaincapsdata/qemu_5.2.0.s390x.xml @@ -249,5 +249,6 @@ <backup supported='no'/> <s390-pv supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_5.2.0.x86_64.xml b/tests/domaincapsdata/qemu_5.2.0.x86_64.xml index 0a6f72df7e..f29152100e 100644 --- a/tests/domaincapsdata/qemu_5.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_5.2.0.x86_64.xml @@ -227,5 +227,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml index 40df34edf0..196568c26f 100644 --- a/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.0.0-q35.x86_64.xml @@ -234,5 +234,6 @@ <maxGuests>59</maxGuests> <maxESGuests>450</maxESGuests> </sev> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml index e563b0cb59..5657a65c47 100644 --- a/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.0.0-tcg.x86_64.xml @@ -248,5 +248,6 @@ <maxGuests>59</maxGuests> <maxESGuests>450</maxESGuests> </sev> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_6.0.0-virt.aarch64.xml index 958c40437f..0a16fe8d51 100644 --- a/tests/domaincapsdata/qemu_6.0.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_6.0.0-virt.aarch64.xml @@ -191,5 +191,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0.aarch64.xml b/tests/domaincapsdata/qemu_6.0.0.aarch64.xml index 4164bf49f7..38e4a1e05c 100644 --- a/tests/domaincapsdata/qemu_6.0.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_6.0.0.aarch64.xml @@ -185,5 +185,6 @@ <backingStoreInput supported='yes'/> <backup supported='no'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0.s390x.xml b/tests/domaincapsdata/qemu_6.0.0.s390x.xml index 13fa3a637e..ccb6536dfc 100644 --- a/tests/domaincapsdata/qemu_6.0.0.s390x.xml +++ b/tests/domaincapsdata/qemu_6.0.0.s390x.xml @@ -250,5 +250,6 @@ <backup supported='no'/> <s390-pv supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.0.0.x86_64.xml b/tests/domaincapsdata/qemu_6.0.0.x86_64.xml index eb60a2105f..0a45267cf5 100644 --- a/tests/domaincapsdata/qemu_6.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.0.0.x86_64.xml @@ -234,5 +234,6 @@ <maxGuests>59</maxGuests> <maxESGuests>450</maxESGuests> </sev> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.1.0-q35.x86_64.xml index 0480a086c6..c75d5d3476 100644 --- a/tests/domaincapsdata/qemu_6.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.1.0-q35.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.1.0-tcg.x86_64.xml index 7baecb0c73..4fbb5a26c9 100644 --- a/tests/domaincapsdata/qemu_6.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.1.0-tcg.x86_64.xml @@ -243,5 +243,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.1.0.x86_64.xml b/tests/domaincapsdata/qemu_6.1.0.x86_64.xml index 9cbe93ad46..572d2e242d 100644 --- a/tests/domaincapsdata/qemu_6.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.1.0.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml index 07b951b81f..a6e2e8f349 100644 --- a/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-q35.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml index 367e656b31..2709dfe28b 100644 --- a/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-tcg.x86_64.xml @@ -244,5 +244,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_6.2.0-virt.aarch64.xml index 99c0fc03fd..ba4d50575b 100644 --- a/tests/domaincapsdata/qemu_6.2.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_6.2.0-virt.aarch64.xml @@ -193,5 +193,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0.aarch64.xml b/tests/domaincapsdata/qemu_6.2.0.aarch64.xml index 8e04508694..9bf6cd7527 100644 --- a/tests/domaincapsdata/qemu_6.2.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.aarch64.xml @@ -187,5 +187,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0.ppc64.xml b/tests/domaincapsdata/qemu_6.2.0.ppc64.xml index 0bbe501383..17b19aaf57 100644 --- a/tests/domaincapsdata/qemu_6.2.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.ppc64.xml @@ -149,5 +149,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml index f363cf1b79..85f9252f63 100644 --- a/tests/domaincapsdata/qemu_6.2.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_6.2.0.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml index 136dadaeb4..59406de113 100644 --- a/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0-q35.x86_64.xml @@ -231,5 +231,15 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <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> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml index c684759356..76ced316c6 100644 --- a/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0-tcg.x86_64.xml @@ -245,5 +245,15 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <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> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0-virt.aarch64.xml b/tests/domaincapsdata/qemu_7.0.0-virt.aarch64.xml index 1d6f29db9f..a6b9abfd49 100644 --- a/tests/domaincapsdata/qemu_7.0.0-virt.aarch64.xml +++ b/tests/domaincapsdata/qemu_7.0.0-virt.aarch64.xml @@ -192,5 +192,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0.aarch64.xml b/tests/domaincapsdata/qemu_7.0.0.aarch64.xml index 73097470f8..f499ba8001 100644 --- a/tests/domaincapsdata/qemu_7.0.0.aarch64.xml +++ b/tests/domaincapsdata/qemu_7.0.0.aarch64.xml @@ -186,5 +186,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0.ppc64.xml b/tests/domaincapsdata/qemu_7.0.0.ppc64.xml index 7765c941c5..46572233d0 100644 --- a/tests/domaincapsdata/qemu_7.0.0.ppc64.xml +++ b/tests/domaincapsdata/qemu_7.0.0.ppc64.xml @@ -150,5 +150,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.0.0.x86_64.xml b/tests/domaincapsdata/qemu_7.0.0.x86_64.xml index 0f9a65ef1b..bf7ad8fe36 100644 --- a/tests/domaincapsdata/qemu_7.0.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.0.0.x86_64.xml @@ -231,5 +231,15 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <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> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml index 30082712f4..6195d94e16 100644 --- a/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0-q35.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml index bcca02f0a4..61097e9431 100644 --- a/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0-tcg.x86_64.xml @@ -243,5 +243,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> diff --git a/tests/domaincapsdata/qemu_7.1.0.x86_64.xml b/tests/domaincapsdata/qemu_7.1.0.x86_64.xml index f377b8e3a9..c9364815f6 100644 --- a/tests/domaincapsdata/qemu_7.1.0.x86_64.xml +++ b/tests/domaincapsdata/qemu_7.1.0.x86_64.xml @@ -230,5 +230,6 @@ <backingStoreInput supported='yes'/> <backup supported='yes'/> <sev supported='no'/> + <sgx supported='no'/> </features> </domainCapabilities> -- 2.25.1

With NUMA config: <devices> ... <memory model='sgx-epc'> <source> <nodemask>0-1</nodemask> </source> <target> <size unit='KiB'>512</size> <node>0</node> </target> </memory> ... </devices> Without NUMA config: <devices> ... <memory model='sgx-epc'> <target> <size unit='KiB'>512</size> </target> </memory> ... </devices> Signed-off-by: Lin Yang <lin.a.yang@intel.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- docs/formatdomain.rst | 25 +++++++- src/conf/domain_conf.c | 30 +++++++++ src/conf/domain_conf.h | 1 + src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 9 +++ src/conf/schemas/domaincommon.rng | 1 + src/qemu/qemu_alias.c | 3 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 48 ++++++++++---- src/qemu/qemu_domain_address.c | 6 ++ src/qemu/qemu_driver.c | 1 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 8 +++ src/security/security_apparmor.c | 1 + src/security/security_dac.c | 2 + src/security/security_selinux.c | 2 + tests/qemuxml2argvdata/sgx-epc.xml | 64 +++++++++++++++++++ .../sgx-epc.x86_64-7.0.0.xml | 1 + tests/qemuxml2xmltest.c | 2 + 19 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 tests/qemuxml2argvdata/sgx-epc.xml create mode 120000 tests/qemuxml2xmloutdata/sgx-epc.x86_64-7.0.0.xml diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 34e4906eb4..728f08158e 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -8001,6 +8001,20 @@ Example: usage of the memory devices <current unit='KiB'>524288</current> </target> </memory> + <memory model='sgx-epc'> + <source> + <nodemask>0-1</nodemask> + </source> + <target> + <size unit='KiB'>16384</size> + <node>0</node> + </target> + </memory> + <memory model='sgx-epc'> + <target> + <size unit='KiB'>16384</size> + </target> + </memory> </devices> ... @@ -8009,7 +8023,9 @@ Example: usage of the memory devices 1.2.14` Provide ``nvdimm`` model that adds a Non-Volatile DIMM module. :since:`Since 3.2.0` Provide ``virtio-pmem`` model to add a paravirtualized persistent memory device. :since:`Since 7.1.0` Provide ``virtio-mem`` model - to add paravirtualized memory device. :since:`Since 7.9.0` + to add paravirtualized memory device. :since:`Since 7.9.0` Provide + ``sgx-epc`` model to add a SGX enclave page cache (EPC) memory to the guest. + :since:`Since 8.9.0 and QEMU 7.0.0` ``access`` An optional attribute ``access`` ( :since:`since 3.2.0` ) that provides @@ -8069,6 +8085,13 @@ Example: usage of the memory devices Represents a path in the host that backs the virtio memory module in the guest. It is mandatory. + For model ``sgx-epc`` this element is optional. The following optional + elements may be used: + + ``nodemask`` + This element can be used to override the default set of NUMA nodes where + the memory would be allocated. :since:`Since 8.9.0 and QEMU 7.0.0` + ``target`` The mandatory ``target`` element configures the placement and sizing of the added memory from the perspective of the guest. diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7dba65cfeb..e260632616 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1443,6 +1443,7 @@ VIR_ENUM_IMPL(virDomainMemoryModel, "nvdimm", "virtio-pmem", "virtio-mem", + "sgx-epc", ); VIR_ENUM_IMPL(virDomainShmemModel, @@ -13154,6 +13155,20 @@ virDomainMemorySourceDefParseXML(xmlNodePtr node, def->nvdimmPath = virXPathString("string(./path)", ctxt); break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if ((nodemask = virXPathString("string(./nodemask)", ctxt))) { + if (virBitmapParse(nodemask, &def->sourceNodes, + VIR_DOMAIN_CPUMASK_LEN) < 0) + return -1; + + if (virBitmapIsAllClear(def->sourceNodes)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid value of 'nodemask': %s"), nodemask); + return -1; + } + } + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -13222,6 +13237,7 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -15020,6 +15036,11 @@ virDomainMemoryFindByDefInternal(virDomainDef *def, continue; break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (!virBitmapEqual(tmp->sourceNodes, mem->sourceNodes)) + continue; + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -24608,6 +24629,15 @@ virDomainMemorySourceDefFormat(virBuffer *buf, virBufferEscapeString(&childBuf, "<path>%s</path>\n", def->nvdimmPath); break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (def->sourceNodes) { + if (!(bitmap = virBitmapFormat(def->sourceNodes))) + return -1; + + virBufferAsprintf(&childBuf, "<nodemask>%s</nodemask>\n", bitmap); + } + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8f8a54bc41..0471d636d9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2582,6 +2582,7 @@ typedef enum { VIR_DOMAIN_MEMORY_MODEL_NVDIMM, /* nvdimm memory device */ VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM, /* virtio-pmem memory device */ VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM, /* virtio-mem memory device */ + VIR_DOMAIN_MEMORY_MODEL_SGX_EPC, /* SGX enclave page cache */ VIR_DOMAIN_MEMORY_MODEL_LAST } virDomainMemoryModel; diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index df59de2d0d..9a3e8f494c 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -645,6 +645,7 @@ virDomainMemoryDefPostParse(virDomainMemoryDef *mem, break; case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index 81f6d5dbd5..5bc7ea10aa 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2360,6 +2360,15 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, case VIR_DOMAIN_MEMORY_MODEL_DIMM: break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("memory device address is not supported for model '%s'"), + virDomainMemoryModelTypeToString(mem->model)); + return -1; + } + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 5ff15e8787..b541277ec0 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6880,6 +6880,7 @@ <value>nvdimm</value> <value>virtio-pmem</value> <value>virtio-mem</value> + <value>sgx-epc</value> </choice> </attribute> <optional> diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index 835401dc07..6061dd3f02 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -513,6 +513,9 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: prefix = "virtiomem"; break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + prefix = "epc"; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 7ec44736d3..df6ce58e23 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3597,6 +3597,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, return NULL; break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 4c14fc2aef..d4c7f971c6 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -8302,6 +8302,7 @@ qemuDomainUpdateMemoryDeviceInfo(virDomainObj *vm, break; case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -8983,6 +8984,12 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem, } break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hotplug is not supported for the %s device"), + virDomainMemoryModelTypeToString(mem->model)); + return -1; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: return -1; @@ -9018,7 +9025,7 @@ int qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, const virDomainMemoryDef *mem) { - unsigned int nmems = def->nmems; + unsigned int hotplugNum = 0; unsigned long long hotplugSpace; unsigned long long hotplugMemory = 0; size_t i; @@ -9026,15 +9033,37 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, hotplugSpace = def->mem.max_memory - virDomainDefGetMemoryInitial(def); if (mem) { - nmems++; + hotplugNum++; hotplugMemory = mem->size; if (qemuDomainDefValidateMemoryHotplugDevice(mem, def) < 0) return -1; } + for (i = 0; i < def->nmems; i++) { + switch (def->mems[i]->model) { + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + hotplugMemory += def->mems[i]->size; + hotplugNum++; + /* already existing devices don't need to be checked on hotplug */ + if (!mem && + qemuDomainDefValidateMemoryHotplugDevice(def->mems[i], def) < 0) + return -1; + break; + + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + /* sgx epc memory does not support hotplug */ + case VIR_DOMAIN_MEMORY_MODEL_LAST: + case VIR_DOMAIN_MEMORY_MODEL_NONE: + break; + } + } + if (!virDomainDefHasMemoryHotplug(def)) { - if (nmems) { + if (hotplugNum) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("cannot use/hotplug a memory device when domain " "'maxMemory' is not defined")); @@ -9057,22 +9086,13 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, } } - if (nmems > def->mem.memory_slots) { + if (hotplugNum > def->mem.memory_slots) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("memory device count '%u' exceeds slots count '%u'"), - nmems, def->mem.memory_slots); + hotplugNum, def->mem.memory_slots); return -1; } - for (i = 0; i < def->nmems; i++) { - hotplugMemory += def->mems[i]->size; - - /* already existing devices don't need to be checked on hotplug */ - if (!mem && - qemuDomainDefValidateMemoryHotplugDevice(def->mems[i], def) < 0) - return -1; - } - if (hotplugMemory > hotplugSpace) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("memory device total size exceeds hotplug space")); diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d8ec6ec71c..b8d1969fbe 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -389,6 +389,7 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -1038,6 +1039,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: return 0; } @@ -2420,6 +2422,7 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -3080,6 +3083,7 @@ qemuDomainAssignMemoryDeviceSlot(virDomainObj *vm, return qemuDomainEnsurePCIAddress(vm, &dev); break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3106,6 +3110,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm, qemuDomainReleaseDeviceAddress(vm, &mem->info); break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3139,6 +3144,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def) case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: /* handled in qemuDomainAssignPCIAddresses() */ break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 40d23b5723..92ef1907ba 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7100,6 +7100,7 @@ qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot modify memory of model '%s'"), diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cec4a64526..7b35593598 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3864,6 +3864,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const virDomainMemoryDef *mem, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: /* None of these can be backed by hugepages. */ return false; @@ -3948,6 +3949,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: /* Backed by user provided path. Not stored in memory * backing dir anyway. */ diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index cb4e32c0ff..9b2b23fecf 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5093,6 +5093,14 @@ qemuValidateDomainDeviceDefMemory(virDomainMemoryDef *mem, } break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("sgx epc isn't supported by this QEMU binary")); + return -1; + } + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 008384dee8..36e8ce42b5 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -687,6 +687,7 @@ AppArmorSetMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 21cebae694..d94995c9cf 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1853,6 +1853,7 @@ virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: ret = 0; @@ -2040,6 +2041,7 @@ virSecurityDACSetMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: ret = 0; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index a296cb7613..1f72f61cac 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -1580,6 +1580,7 @@ virSecuritySELinuxSetMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -1608,6 +1609,7 @@ virSecuritySELinuxRestoreMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: ret = 0; diff --git a/tests/qemuxml2argvdata/sgx-epc.xml b/tests/qemuxml2argvdata/sgx-epc.xml new file mode 100644 index 0000000000..62212f3401 --- /dev/null +++ b/tests/qemuxml2argvdata/sgx-epc.xml @@ -0,0 +1,64 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='pc-q35-7.0'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + <numa> + <cell id='0' cpus='0' memory='109550' unit='KiB'/> + <cell id='1' cpus='1' memory='109550' unit='KiB'/> + </numa> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </memballoon> + <memory model='sgx-epc'> + <source> + <nodemask>0-1</nodemask> + </source> + <target> + <size unit='KiB'>65536</size> + <node>0</node> + </target> + </memory> + <memory model='sgx-epc'> + <source> + <nodemask>2-3</nodemask> + </source> + <target> + <size unit='KiB'>16384</size> + <node>1</node> + </target> + </memory> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/sgx-epc.x86_64-7.0.0.xml b/tests/qemuxml2xmloutdata/sgx-epc.x86_64-7.0.0.xml new file mode 120000 index 0000000000..cc2263ac99 --- /dev/null +++ b/tests/qemuxml2xmloutdata/sgx-epc.x86_64-7.0.0.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/sgx-epc.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 3a2d029c4f..301406fc1d 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -1312,6 +1312,8 @@ mymain(void) DO_TEST_CAPS_LATEST("channel-qemu-vdagent"); DO_TEST_CAPS_LATEST("channel-qemu-vdagent-features"); + DO_TEST_CAPS_VER("sgx-epc", "7.0.0"); + cleanup: if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.25.1

On 10/8/22 06:00, Lin Yang wrote:
With NUMA config:
<devices> ... <memory model='sgx-epc'> <source> <nodemask>0-1</nodemask> </source> <target> <size unit='KiB'>512</size> <node>0</node> </target> </memory> ... </devices>
Without NUMA config:
<devices> ... <memory model='sgx-epc'> <target> <size unit='KiB'>512</size> </target> </memory> ... </devices>
Patches look good to me. And I'd like to merge them. However, in one of previous iterations Peter raised a concern whether this should be exposed as something else than <memory model='sgx-epc'/>. One fact that would support this is that SGX 'cuts' from guest memory. I mean, memory backend-epc does not add more RAM into the guest: # ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu) Which is also the reason why we need to special case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC so much. On the other hand, the fact that QEMU exposes it as a memory backend means, that it kind of falls into <memory/> category. So my question then is, Peter, are you okay with leaving this under <memory/> or do you have other suggestion? Michal

On 10/14/22 13:12, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
With NUMA config:
<devices> ... <memory model='sgx-epc'> <source> <nodemask>0-1</nodemask> </source> <target> <size unit='KiB'>512</size> <node>0</node> </target> </memory> ... </devices>
Without NUMA config:
<devices> ... <memory model='sgx-epc'> <target> <size unit='KiB'>512</size> </target> </memory> ... </devices>
Patches look good to me. And I'd like to merge them. However, in one of previous iterations Peter raised a concern whether this should be exposed as something else than <memory model='sgx-epc'/>. One fact that would support this is that SGX 'cuts' from guest memory. I mean, memory backend-epc does not add more RAM into the guest:
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
Which is also the reason why we need to special case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC so much.
On the other hand, the fact that QEMU exposes it as a memory backend means, that it kind of falls into <memory/> category.
So my question then is, Peter, are you okay with leaving this under <memory/> or do you have other suggestion?
Maybe Dan can help us here? Michal

On Fri, Oct 14, 2022 at 01:12:28PM +0200, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
With NUMA config:
<devices> ... <memory model='sgx-epc'> <source> <nodemask>0-1</nodemask> </source> <target> <size unit='KiB'>512</size> <node>0</node> </target> </memory> ... </devices>
Without NUMA config:
<devices> ... <memory model='sgx-epc'> <target> <size unit='KiB'>512</size> </target> </memory> ... </devices>
Patches look good to me. And I'd like to merge them. However, in one of previous iterations Peter raised a concern whether this should be exposed as something else than <memory model='sgx-epc'/>. One fact that would support this is that SGX 'cuts' from guest memory. I mean, memory backend-epc does not add more RAM into the guest:
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
I'm not sure this check is showing us the truth. In backends/hostmem-epc.c, sgx_epc_backend_memory_alloc is opening /dev/sgx_vepc and mmap()ing the requested size from that file. IOW that's clearly in addition to whatever has been mapped as the main RAM. In hw/i386/sgx-epc.c, sgx_epc_md_get_plugged_size is hardcoded to always return 0, which is why 'plugged memory' is reported as zero above. I don't know what it is reporting zero. Is this because the SGX RAM is not accessible to the guest OS as "normal" RAM perhaps, and thus to be reported differently. With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Tue, Nov 08, 2022 at 12:25:26 +0000, Daniel P. Berrangé wrote:
On Fri, Oct 14, 2022 at 01:12:28PM +0200, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
[...]
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
I'm not sure this check is showing us the truth.
In backends/hostmem-epc.c, sgx_epc_backend_memory_alloc is opening /dev/sgx_vepc and mmap()ing the requested size from that file. IOW that's clearly in addition to whatever has been mapped as the main RAM.
In hw/i386/sgx-epc.c, sgx_epc_md_get_plugged_size is hardcoded to always return 0, which is why 'plugged memory' is reported as zero above. I don't know what it is reporting zero.
Is this because the SGX RAM is not accessible to the guest OS as "normal" RAM perhaps, and thus to be reported differently.
So even if the memory is not accessible as normal RAM, but still is usable by the guest OS, the use of an <devices><memory> element is okay, but the total memory size of a VM should account for it. So in fact all the hacks which exclude it from the total memory size should be removed.

On 11/8/22, 5:16 AM, "Peter Krempa" <pkrempa@redhat.com> wrote:
On Tue, Nov 08, 2022 at 12:25:26 +0000, Daniel P. Berrangé wrote:
On Fri, Oct 14, 2022 at 01:12:28PM +0200, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
[...]
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
I'm not sure this check is showing us the truth.
In backends/hostmem-epc.c, sgx_epc_backend_memory_alloc is opening /dev/sgx_vepc and mmap()ing the requested size from that file. IOW that's clearly in addition to whatever has been mapped as the main RAM.
In hw/i386/sgx-epc.c, sgx_epc_md_get_plugged_size is hardcoded to always return 0, which is why 'plugged memory' is reported as zero above. I don't know what it is reporting zero.
Is this because the SGX RAM is not accessible to the guest OS as "normal" RAM perhaps, and thus to be reported differently.
So even if the memory is not accessible as normal RAM, but still is usable by the guest OS, the use of an <devices><memory> element is okay, but the total memory size of a VM should account for it.
So in fact all the hacks which exclude it from the total memory size should be removed.
QEMU reports zero 'plugged memory' for SGX RAM because it will not add more normal RAM to guest OS and it cannot be hotplug/unplug on the fly, since it is realized through CPUID and has to be initialized before vcpu. One the host, BIOS reserves part of RAM as SGX RAM, which cannot be directly accessed by other application or kernel. The host OS only see RAM size = physical memory size – SGX RAM. Does “total memory size” here means all memory device size, like all physical memory size on host, not normal RAM size? If not, it might give confusing info to user since guset OS shows a different normal RAM size. Really appreciated all your reviewing. Regards, Lin.

On Thu, Nov 10, 2022 at 06:09:46 +0000, Yang, Lin A wrote:
On 11/8/22, 5:16 AM, "Peter Krempa" <pkrempa@redhat.com> wrote:
On Tue, Nov 08, 2022 at 12:25:26 +0000, Daniel P. Berrangé wrote:
On Fri, Oct 14, 2022 at 01:12:28PM +0200, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
[...]
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
I'm not sure this check is showing us the truth.
In backends/hostmem-epc.c, sgx_epc_backend_memory_alloc is opening /dev/sgx_vepc and mmap()ing the requested size from that file. IOW that's clearly in addition to whatever has been mapped as the main RAM.
In hw/i386/sgx-epc.c, sgx_epc_md_get_plugged_size is hardcoded to always return 0, which is why 'plugged memory' is reported as zero above. I don't know what it is reporting zero.
Is this because the SGX RAM is not accessible to the guest OS as "normal" RAM perhaps, and thus to be reported differently.
So even if the memory is not accessible as normal RAM, but still is usable by the guest OS, the use of an <devices><memory> element is okay, but the total memory size of a VM should account for it.
So in fact all the hacks which exclude it from the total memory size should be removed.
QEMU reports zero 'plugged memory' for SGX RAM because it will not add more normal RAM to guest OS and it cannot be hotplug/unplug on the fly, since it is realized through CPUID and has to be initialized before vcpu.
One the host, BIOS reserves part of RAM as SGX RAM, which cannot be directly accessed by other application or kernel. The host OS only see RAM size = physical memory size – SGX RAM.
Does “total memory size” here means all memory device size, like all physical memory size on host, not normal RAM size? If not, it might give confusing info to user since guset OS shows a different normal RAM size.
Libvirt's total memory size must include any memory usable by the guest OS regardless of how it is made available to it and regardless of whether un-modified OS is able to use it. Same applies e.g. to virtio-mem which requires a guest driver. Similarly the EPC memory most likely is provided to the guest via normal memory mapping (If not make sure to explicitly point it out next time.) and thus also must be included in the calculation and validation of maximum memory address space. This calculation/validation is done in qemuDomainDefValidateMemoryHotplug and thus is correct and EPC must be included in it. The funciton and variable naming may be confusing so you can change it, but functionally it seems it must be included in the calculation.

On 11/9/22, 11:37 PM, "Peter Krempa" <pkrempa@redhat.com> wrote:
On Thu, Nov 10, 2022 at 06:09:46 +0000, Yang, Lin A wrote:
On 11/8/22, 5:16 AM, "Peter Krempa" <pkrempa@redhat.com> wrote:
On Tue, Nov 08, 2022 at 12:25:26 +0000, Daniel P. Berrangé wrote:
On Fri, Oct 14, 2022 at 01:12:28PM +0200, Michal Prívozník wrote:
On 10/8/22 06:00, Lin Yang wrote:
[...]
# ./qemu-system-x86_64 -S -nographic -nodefaults -m 128 \ -machine pc,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0 \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0],"policy":"bind"}' \ -monitor stdio QEMU 7.1.50 monitor - type 'help' for more information (qemu) info memory-devices Memory device [sgx-epc]: "" memaddr: 0x100000000 size: 67108864 node: 0 memdev: /objects/memepc0 (qemu) info memory_size_summary base memory: 134217728 plugged memory: 0 (qemu)
I'm not sure this check is showing us the truth.
In backends/hostmem-epc.c, sgx_epc_backend_memory_alloc is opening /dev/sgx_vepc and mmap()ing the requested size from that file. IOW that's clearly in addition to whatever has been mapped as the main RAM.
In hw/i386/sgx-epc.c, sgx_epc_md_get_plugged_size is hardcoded to always return 0, which is why 'plugged memory' is reported as zero above. I don't know what it is reporting zero.
Is this because the SGX RAM is not accessible to the guest OS as "normal" RAM perhaps, and thus to be reported differently.
So even if the memory is not accessible as normal RAM, but still is usable by the guest OS, the use of an <devices><memory> element is okay, but the total memory size of a VM should account for it.
So in fact all the hacks which exclude it from the total memory size should be removed.
QEMU reports zero 'plugged memory' for SGX RAM because it will not add more normal RAM to guest OS and it cannot be hotplug/unplug on the fly, since it is realized through CPUID and has to be initialized before vcpu.
One the host, BIOS reserves part of RAM as SGX RAM, which cannot be directly accessed by other application or kernel. The host OS only see RAM size = physical memory size – SGX RAM.
Does “total memory size” here means all memory device size, like all physical memory size on host, not normal RAM size? If not, it might give confusing info to user since guset OS shows a different normal RAM size.
Libvirt's total memory size must include any memory usable by the guest OS regardless of how it is made available to it and regardless of whether un-modified OS is able to use it. Same applies e.g. to virtio-mem which requires a guest driver.
Similarly the EPC memory most likely is provided to the guest via normal memory mapping (If not make sure to explicitly point it out next time.) and thus also must be included in the calculation and validation of maximum memory address space. This calculation/validation is done in qemuDomainDefValidateMemoryHotplug and thus is correct and EPC must be included in it. The funciton and variable naming may be confusing so you can change it, but functionally it seems it must be included in the calculation.
Thank you so much for explanation in details. True, EPC is mapped to separate memory region in guest via mmap(). It’s clear to me now. Let me quickly resolve it in next patch. Regards, Lin.

From: Michal Privoznik <mprivozn@redhat.com> SGX memory backend needs to access /dev/sgx_vepc (which allows userspace to allocate "raw" EPC without an associated enclave) and /dev/sgx_provision (which allows creating provisioning enclaves). Allow these two devices in CGroups if a domain is configured so. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/qemu/qemu_cgroup.c | 78 +++++++++++++++++++++++++++++++++++------- src/qemu/qemu_domain.h | 2 ++ 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index d6f27a5a4d..9cd4bf8b98 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -120,6 +120,28 @@ qemuCgroupDenyDevicePath(virDomainObj *vm, } +static int +qemuCgroupDenyDevicesPaths(virDomainObj *vm, + const char *const *paths, + int perms, + bool ignoreEacces) +{ + size_t i; + + for (i = 0; paths[i] != NULL; i++) { + if (!virFileExists(paths[i])) { + VIR_DEBUG("Ignoring non-existent device %s", paths[i]); + continue; + } + + if (qemuCgroupDenyDevicePath(vm, paths[i], perms, ignoreEacces) < 0) + return -1; + } + + return 0; +} + + static int qemuSetupImagePathCgroup(virDomainObj *vm, const char *path, @@ -520,16 +542,32 @@ qemuSetupMemoryDevicesCgroup(virDomainObj *vm, virDomainMemoryDef *mem) { qemuDomainObjPrivate *priv = vm->privateData; - - if (mem->model != VIR_DOMAIN_MEMORY_MODEL_NVDIMM && - mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM) - return 0; + const char *const sgxPaths[] = { QEMU_DEV_SGX_VEPVC, + QEMU_DEV_SGX_PROVISION, NULL }; if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) return 0; - return qemuCgroupAllowDevicePath(vm, mem->nvdimmPath, - VIR_CGROUP_DEVICE_RW, false); + switch (mem->model) { + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + if (qemuCgroupAllowDevicePath(vm, mem->nvdimmPath, + VIR_CGROUP_DEVICE_RW, false) < 0) + return -1; + break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (qemuCgroupAllowDevicesPaths(vm, sgxPaths, + VIR_CGROUP_DEVICE_RW, false) < 0) + return -1; + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + break; + } + + return 0; } @@ -538,16 +576,32 @@ qemuTeardownMemoryDevicesCgroup(virDomainObj *vm, virDomainMemoryDef *mem) { qemuDomainObjPrivate *priv = vm->privateData; - - if (mem->model != VIR_DOMAIN_MEMORY_MODEL_NVDIMM && - mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM) - return 0; + const char *const sgxPaths[] = { QEMU_DEV_SGX_VEPVC, + QEMU_DEV_SGX_PROVISION, NULL }; if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) return 0; - return qemuCgroupDenyDevicePath(vm, mem->nvdimmPath, - VIR_CGROUP_DEVICE_RWM, false); + switch (mem->model) { + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + if (qemuCgroupDenyDevicePath(vm, mem->nvdimmPath, + VIR_CGROUP_DEVICE_RWM, false) < 0) + return -1; + break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + if (qemuCgroupDenyDevicesPaths(vm, sgxPaths, + VIR_CGROUP_DEVICE_RW, false) < 0) + return -1; + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + break; + } + + return 0; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a22deaf113..2eedbbf6f7 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -81,6 +81,8 @@ struct _qemuDomainUnpluggingDevice { #define QEMU_DEVPREFIX "/dev/" #define QEMU_DEV_VFIO "/dev/vfio/vfio" #define QEMU_DEV_SEV "/dev/sev" +#define QEMU_DEV_SGX_VEPVC "/dev/sgx_vepc" +#define QEMU_DEV_SGX_PROVISION "/dev/sgx_provision" #define QEMU_DEVICE_MAPPER_CONTROL_PATH "/dev/mapper/control" -- 2.25.1

From: Michal Privoznik <mprivozn@redhat.com> This is similar to the previous commit. SGX memory backend needs to access /dev/sgx_vepc and /dev/sgx_provision. Create these nodes in domain's private /dev when required by domain's config. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/qemu/qemu_namespace.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c index 311c66d46e..4a96460122 100644 --- a/src/qemu/qemu_namespace.c +++ b/src/qemu/qemu_namespace.c @@ -358,11 +358,23 @@ static int qemuDomainSetupMemory(virDomainMemoryDef *mem, GSList **paths) { - if (mem->model != VIR_DOMAIN_MEMORY_MODEL_NVDIMM && - mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM) - return 0; + switch (mem->model) { + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + *paths = g_slist_prepend(*paths, g_strdup(mem->nvdimmPath)); + break; + + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + *paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_VEPVC)); + *paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_PROVISION)); + break; - *paths = g_slist_prepend(*paths, g_strdup(mem->nvdimmPath)); + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + break; + } return 0; } -- 2.25.1

From: Michal Privoznik <mprivozn@redhat.com> As advertised in previous commits, QEMU needs to access /dev/sgx_vepc and /dev/sgx_provision files when SGX memory backend is configured. And if it weren't for QEMU's namespaces, we wouldn't dare to relabel them, because they are system wide files. But if namespaces are used, then we can set label on domain's private copies, just like we do for /dev/sev. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/security/security_dac.c | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index d94995c9cf..5ca63e30f4 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -48,6 +48,8 @@ VIR_LOG_INIT("security.security_dac"); #define SECURITY_DAC_NAME "dac" #define DEV_SEV "/dev/sev" +#define DEV_SGX_VEPC "/dev/sgx_vepc" +#define DEV_SGX_PROVISION "/dev/sgx_provision" typedef struct _virSecurityDACData virSecurityDACData; struct _virSecurityDACData { @@ -1843,24 +1845,24 @@ virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr, virDomainDef *def G_GNUC_UNUSED, virDomainMemoryDef *mem) { - int ret = -1; - switch (mem->model) { case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: - ret = virSecurityDACRestoreFileLabel(mgr, mem->nvdimmPath); + return virSecurityDACRestoreFileLabel(mgr, mem->nvdimmPath); + + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + /* We set label on SGX /dev nodes iff running with namespaces, so we + * don't need to restore anything. */ break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: - case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: - ret = 0; break; } - return ret; + return 0; } @@ -2020,35 +2022,43 @@ virSecurityDACSetMemoryLabel(virSecurityManager *mgr, { virSecurityDACData *priv = virSecurityManagerGetPrivateData(mgr); virSecurityLabelDef *seclabel; - int ret = -1; uid_t user; gid_t group; + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); + if (seclabel && !seclabel->relabel) + return 0; + + if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0) + return -1; + switch (mem->model) { case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: - seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); - if (seclabel && !seclabel->relabel) - return 0; + return virSecurityDACSetOwnership(mgr, NULL, + mem->nvdimmPath, + user, group, true); - if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL) < 0) + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + /* Skip chowning SGX if namespaces are disabled. */ + if (priv->mountNamespace && + (virSecurityDACSetOwnership(mgr, NULL, + DEV_SGX_VEPC, + user, group, true) < 0 || + virSecurityDACSetOwnership(mgr, NULL, + DEV_SGX_PROVISION, + user, group, true) < 0)) return -1; - - ret = virSecurityDACSetOwnership(mgr, NULL, - mem->nvdimmPath, - user, group, true); break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: - case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: - ret = 0; break; } - return ret; + return 0; } -- 2.25.1

According to the result parsing from xml, add the argument of SGX EPC memory backend into QEMU command line. With NUMA config: #qemu-system-x86_64 \ ...... \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0,1],"policy":"bind"}' \ -object '{"qom-type":"memory-backend-epc","id":"memepc1","prealloc":true,"size":16777216,"host-nodes":[2,3],"policy":"bind"}' \ -machine sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0,sgx-epc.1.memdev=memepc1,sgx-epc.1.node=1 Without NUMA config: #qemu-system-x86_64 \ ...... \ -object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864}' \ -object '{"qom-type":"memory-backend-epc","id":"memepc1","prealloc":true,"size":16777216}' \ -machine sgx-epc.0.memdev=memepc0,sgx-epc.1.memdev=memepc1 Signed-off-by: Lin Yang <lin.a.yang@intel.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Haibin Huang <haibin.huang@intel.com> --- src/qemu/qemu_alias.c | 3 +- src/qemu/qemu_command.c | 65 ++++++++++++++++--- src/qemu/qemu_monitor_json.c | 41 ++++++++++-- src/qemu/qemu_validate.c | 32 +++++++++ .../sgx-epc.x86_64-7.0.0.args | 40 ++++++++++++ tests/qemuxml2argvdata/sgx-epc.xml | 10 +-- tests/qemuxml2argvtest.c | 2 + 7 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 tests/qemuxml2argvdata/sgx-epc.x86_64-7.0.0.args diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index 6061dd3f02..ef8e87ab58 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -464,7 +464,8 @@ qemuDeviceMemoryGetAliasID(virDomainDef *def, * valid */ if (!oldAlias && mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM && - mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM) + mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM && + mem->model != VIR_DOMAIN_MEMORY_MODEL_SGX_EPC) return mem->info.addr.dimm.slot; for (i = 0; i < def->nmems; i++) { diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index df6ce58e23..f11c67858f 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3314,7 +3314,11 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, props = virJSONValueNewObject(); - if (!mem->nvdimmPath && + if (mem->model == VIR_DOMAIN_MEMORY_MODEL_SGX_EPC) { + backendType = "memory-backend-epc"; + if (!priv->memPrealloc) + prealloc = true; + } else if (!mem->nvdimmPath && def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_MEMFD) { backendType = "memory-backend-memfd"; @@ -3329,7 +3333,6 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, if (systemMemory) disableCanonicalPath = true; - } else if (useHugepage || mem->nvdimmPath || memAccess || def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) { @@ -6626,6 +6629,8 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf, const virDomainDef *def, virQEMUCaps *qemuCaps) { + bool nvdimmAdded = false; + int epcNum = 0; size_t i; if (def->mem.dump_core) { @@ -6640,8 +6645,36 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf, virBufferAddLit(buf, ",mem-merge=off"); for (i = 0; i < def->nmems; i++) { - if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) { - virBufferAddLit(buf, ",nvdimm=on"); + int targetNode = def->mems[i]->targetNode; + + switch (def->mems[i]->model) { + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + if (!nvdimmAdded) { + virBufferAddLit(buf, ",nvdimm=on"); + nvdimmAdded = true; + } + break; + + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + /* add sgx epc memory to -machine parameter */ + + if (targetNode < 0) { + /* set NUMA target node to 0 by default if user doesn't + * specify it. */ + targetNode = 0; + } + + virBufferAsprintf(buf, ",sgx-epc.%d.memdev=mem%s,sgx-epc.%d.node=%d", + epcNum, def->mems[i]->info.alias, epcNum, targetNode); + + epcNum++; + break; + + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } } @@ -7358,11 +7391,27 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd, if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 0) return -1; - if (!(props = qemuBuildMemoryDeviceProps(cfg, priv, def, def->mems[i]))) - return -1; + switch (def->mems[i]->model) { + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: + case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + if (!(props = qemuBuildMemoryDeviceProps(cfg, priv, def, def->mems[i]))) + return -1; - if (qemuBuildDeviceCommandlineFromJSON(cmd, props, def, priv->qemuCaps) < 0) - return -1; + if (qemuBuildDeviceCommandlineFromJSON(cmd, props, def, priv->qemuCaps) < 0) + return -1; + + break; + + /* sgx epc memory will be added to -machine parameter, so skip here */ + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + break; + + case VIR_DOMAIN_MEMORY_MODEL_NONE: + case VIR_DOMAIN_MEMORY_MODEL_LAST: + break; + } } return 0; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 32e0c2ff17..cb3b6df072 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7213,13 +7213,25 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon, return -1; } - /* While 'id' attribute is marked as optional in QEMU's QAPI - * specification, Libvirt always sets it. Thus we can fail if not - * present. */ - if (!(devalias = virJSONValueObjectGetString(dimminfo, "id"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("dimm memory info data is missing 'id'")); - return -1; + if (STREQ(type, "dimm") || STREQ(type, "nvdimm") || STREQ(type, "virtio-mem")) { + /* While 'id' attribute is marked as optional in QEMU's QAPI + * specification, Libvirt always sets it. Thus we can fail if not + * present. */ + if (!(devalias = virJSONValueObjectGetString(dimminfo, "id"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("dimm memory info data is missing 'id'")); + return -1; + } + } else if (STREQ(type, "sgx-epc")) { + if (!(devalias = virJSONValueObjectGetString(dimminfo, "memdev"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("sgx-epc memory info data is missing 'memdev'")); + return -1; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s memory device info is not handled yet"), type); + return -1; } meminfo = g_new0(qemuMonitorMemoryDeviceInfo, 1); @@ -7263,6 +7275,21 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon, _("malformed/missing size in virtio memory info")); return -1; } + } else if (STREQ(type, "sgx-epc")) { + /* sgx-epc memory devices */ + if (virJSONValueObjectGetNumberUlong(dimminfo, "memaddr", + &meminfo->address) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing memaddr in sgx-epc memory info")); + return -1; + } + + if (virJSONValueObjectGetNumberUlong(dimminfo, "size", + &meminfo->size) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed/missing size in sgx-epc memory info")); + return -1; + } } else { /* type not handled yet */ continue; diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 9b2b23fecf..b0d05ab8eb 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5052,6 +5052,9 @@ static int qemuValidateDomainDeviceDefMemory(virDomainMemoryDef *mem, virQEMUCaps *qemuCaps) { + virSGXCapability *sgxCaps; + ssize_t node = -1; + switch (mem->model) { case VIR_DOMAIN_MEMORY_MODEL_DIMM: if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) { @@ -5099,6 +5102,35 @@ qemuValidateDomainDeviceDefMemory(virDomainMemoryDef *mem, _("sgx epc isn't supported by this QEMU binary")); return -1; } + + sgxCaps = virQEMUCapsGetSGXCapabilities(qemuCaps); + + if (sgxCaps->nSgxSections == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("this QEMU version didn't provide SGX EPC NUMA info")); + return -1; + } + + if (mem->sourceNodes) { + while ((node = virBitmapNextSetBit(mem->sourceNodes, node)) >= 0) { + if (mem->size > sgxCaps->sgxSections[node].size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("sgx epc size %lld on host node %ld is less than requested size %lld"), + sgxCaps->sgxSections[node].size, node, mem->size); + return -1; + } + } + } else { + /* allocate epc from host node 0 by default if user doesn't + * specify it. */ + if (mem->size > sgxCaps->sgxSections[0].size) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("sgx epc size %lld on host node %d is less than requested size %lld"), + sgxCaps->sgxSections[0].size, 0, mem->size); + return -1; + } + } + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: diff --git a/tests/qemuxml2argvdata/sgx-epc.x86_64-7.0.0.args b/tests/qemuxml2argvdata/sgx-epc.x86_64-7.0.0.args new file mode 100644 index 0000000000..cc4260fb94 --- /dev/null +++ b/tests/qemuxml2argvdata/sgx-epc.x86_64-7.0.0.args @@ -0,0 +1,40 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc-q35-7.0,usb=off,dump-guest-core=off,sgx-epc.0.memdev=memepc0,sgx-epc.0.node=0,sgx-epc.1.memdev=memepc1,sgx-epc.1.node=1 \ +-accel tcg \ +-cpu qemu64 \ +-m 1024 \ +-overcommit mem-lock=off \ +-smp 2,sockets=2,cores=1,threads=1 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node0","size":536870912}' \ +-numa node,nodeid=0,cpus=0,memdev=ram-node0 \ +-object '{"qom-type":"memory-backend-ram","id":"ram-node1","size":536870912}' \ +-numa node,nodeid=1,cpus=1,memdev=ram-node1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \ +-object '{"qom-type":"memory-backend-epc","id":"memepc0","prealloc":true,"size":67108864,"host-nodes":[0,1],"policy":"bind"}' \ +-object '{"qom-type":"memory-backend-epc","id":"memepc1","prealloc":true,"size":16777216,"host-nodes":[0,1],"policy":"bind"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.1","addr":"0x0"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/sgx-epc.xml b/tests/qemuxml2argvdata/sgx-epc.xml index 62212f3401..65be135698 100644 --- a/tests/qemuxml2argvdata/sgx-epc.xml +++ b/tests/qemuxml2argvdata/sgx-epc.xml @@ -1,8 +1,8 @@ <domain type='qemu'> <name>QEMUGuest1</name> <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> - <memory unit='KiB'>219100</memory> - <currentMemory unit='KiB'>219100</currentMemory> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>1048576</currentMemory> <vcpu placement='static'>2</vcpu> <os> <type arch='x86_64' machine='pc-q35-7.0'>hvm</type> @@ -11,8 +11,8 @@ <cpu mode='custom' match='exact' check='none'> <model fallback='forbid'>qemu64</model> <numa> - <cell id='0' cpus='0' memory='109550' unit='KiB'/> - <cell id='1' cpus='1' memory='109550' unit='KiB'/> + <cell id='0' cpus='0' memory='524288' unit='KiB'/> + <cell id='1' cpus='1' memory='524288' unit='KiB'/> </numa> </cpu> <clock offset='utc'/> @@ -53,7 +53,7 @@ </memory> <memory model='sgx-epc'> <source> - <nodemask>2-3</nodemask> + <nodemask>0-1</nodemask> </source> <target> <size unit='KiB'>16384</size> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f40eac4fe8..36a3dd3b64 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -3182,6 +3182,8 @@ mymain(void) DO_TEST_PARSE_ERROR("cpu-phys-bits-emulate3", QEMU_CAPS_KVM); DO_TEST_PARSE_ERROR("cpu-phys-bits-passthrough2", QEMU_CAPS_KVM); + DO_TEST_CAPS_VER("sgx-epc", "7.0.0"); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.25.1
participants (5)
-
Daniel P. Berrangé
-
Lin Yang
-
Michal Prívozník
-
Peter Krempa
-
Yang, Lin A