Convert QMP capabilities to domain capabilities

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>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Haibin Huang 2022-11-10 17:21:21 -08:00 committed by Michal Privoznik
parent 1a68499c01
commit 6b7c36c8c2
7 changed files with 300 additions and 16 deletions

View File

@ -677,6 +677,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
/* 435 */
"query-stats", /* QEMU_CAPS_QUERY_STATS */
"query-stats-schemas", /* QEMU_CAPS_QUERY_STATS_SCHEMAS */
"sgx-epc", /* QEMU_CAPS_SGX_EPC */
);
@ -758,6 +759,8 @@ struct _virQEMUCaps {
virSEVCapability *sevCapabilities;
virSGXCapability *sgxCapabilities;
/* Capabilities which may differ depending on the accelerator. */
virQEMUCapsAccel kvm;
virQEMUCapsAccel hvf;
@ -1380,6 +1383,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 },
};
@ -1891,6 +1895,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)
@ -1972,6 +2006,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);
}
@ -2010,6 +2050,7 @@ void virQEMUCapsDispose(void *obj)
virCPUDataFree(qemuCaps->cpuData);
virSEVCapabilitiesFree(qemuCaps->sevCapabilities);
virSGXCapabilitiesFree(qemuCaps->sgxCapabilities);
virQEMUCapsAccelClear(&qemuCaps->kvm);
virQEMUCapsAccelClear(&qemuCaps->hvf);
@ -2541,6 +2582,13 @@ virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps)
}
virSGXCapability *
virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps)
{
return qemuCaps->sgxCapabilities;
}
static int
virQEMUCapsProbeQMPCommands(virQEMUCaps *qemuCaps,
qemuMonitor *mon)
@ -3373,6 +3421,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
@ -4167,6 +4240,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, &sectionNodes);
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)
{
@ -4455,6 +4619,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))
@ -4643,6 +4810,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)
{
@ -4724,6 +4923,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
if (qemuCaps->sevCapabilities)
virQEMUCapsFormatSEVInfo(qemuCaps, &buf);
if (qemuCaps->sgxCapabilities)
virQEMUCapsFormatSGXInfo(qemuCaps, &buf);
if (qemuCaps->kvmSupportsNesting)
virBufferAddLit(&buf, "<kvmSupportsNesting/>\n");
@ -5353,6 +5555,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps,
return -1;
if (virQEMUCapsProbeQMPSEVCapabilities(qemuCaps, mon) < 0)
return -1;
if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0)
return -1;
virQEMUCapsInitProcessCaps(qemuCaps);

View File

@ -656,6 +656,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
/* 435 */
QEMU_CAPS_QUERY_STATS, /* accepts query-stats */
QEMU_CAPS_QUERY_STATS_SCHEMAS, /* accepts query-stats-schemas */
QEMU_CAPS_SGX_EPC, /* -object sgx-epc,... */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
@ -859,6 +860,9 @@ virQEMUCapsCPUFeatureFromQEMUInPlace(virArch arch,
virSEVCapability *
virQEMUCapsGetSEVCapabilities(virQEMUCaps *qemuCaps);
virSGXCapability *
virQEMUCapsGetSGXCapabilities(virQEMUCaps *qemuCaps);
bool
virQEMUCapsGetKVMSupportsSecureGuest(virQEMUCaps *qemuCaps) G_NO_INLINE;

View File

@ -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"
}
{

View File

@ -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"
}
{

View File

@ -195,6 +195,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>
@ -3723,4 +3724,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>

View File

@ -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"
}
{

View File

@ -34635,6 +34635,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": {
@ -34643,7 +34656,7 @@
"name": "host"
}
},
"id": "libvirt-48"
"id": "libvirt-49"
}
{
@ -34981,7 +34994,7 @@
}
}
},
"id": "libvirt-48"
"id": "libvirt-49"
}
{
@ -34995,7 +35008,7 @@
}
}
},
"id": "libvirt-49"
"id": "libvirt-50"
}
{
@ -35333,7 +35346,7 @@
}
}
},
"id": "libvirt-49"
"id": "libvirt-50"
}
{