QEMU has -fw_cfg which allows users to tweak how firmware configures itself and/or provide new configuration blobs. Introduce new <sysinfo/> type "fwcfg" that will hold these new blobs. It's possible to either specify new value as a string or provide a filename which contents then serve as the value. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- docs/formatdomain.html.in | 32 +++ docs/schemas/domaincommon.rng | 143 ++++++++------ src/conf/domain_conf.c | 186 +++++++++++++----- src/conf/domain_conf.h | 4 +- src/qemu/qemu_command.c | 10 +- src/util/virsysinfo.c | 54 ++++- src/util/virsysinfo.h | 16 +- tests/qemuxml2argvdata/smbios-type-fwcfg.xml | 63 ++++++ .../qemuxml2xmloutdata/smbios-type-fwcfg.xml | 1 + tests/qemuxml2xmltest.c | 1 + 10 files changed, 396 insertions(+), 114 deletions(-) create mode 100644 tests/qemuxml2argvdata/smbios-type-fwcfg.xml create mode 120000 tests/qemuxml2xmloutdata/smbios-type-fwcfg.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 33cec1e6dd..6e51aad8b1 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -479,6 +479,10 @@ <entry>otherappname:more arbitrary data</entry> </oemStrings> </sysinfo> +<sysinfo type='fwcfg'> + <entry name='opt/com.example/name' value='example value'/> + <entry name='opt/com.coreos/config' file='/tmp/provision.ign'/> +</sysinfo> ...</pre> <p> @@ -593,6 +597,34 @@ </dd> </dl> </dd> + + <dt><code>fwcfg</code></dt> + <dd> + Some hypervisors provide unified way to tweak how firmware configures + itself, or may contain tables to be installed for the guest OS, for + instance boot order, ACPI, SMBIOS, etc. It even allows users to define + their own config blobs. In case of QEMU, these then appear under domain's + sysfs, under <code>/sys/firmware/qemu_fw_cfg</code>. Note, that these + values apply regardless the <smbios/> mode under <os/>. + <span class="since">Since 6.5.0</span> + +<pre> + <smbios type='fwcfg'> + <entry name="opt/com.example/name" value="example value"/> + <entry name="opt/com.coreos/config" file="/tmp/provision.ign"/> + </smbios> +</pre> + + The <code>smbios</code> element can have multiple <code>entry</code> + child elements. Each element then has mandatory <code>name</code> + attribute, which defines the name of the blob and must begin with + <code>"opt/"</code> and to avoid clashing with other names is advised to + be in form <code>"opt/$RFQDN/$name"</code> where <code>$RFQDN</code> is a + reverse fully qualified domain name you control. + Then, the element can have either <code>value</code> attribute (to set + the blob value directly), or <code>file</code> attribute (to set the blob + value from the file). + </dd> </dl> <h3><a id="elementsCPUAllocation">CPU Allocation</a></h3> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6727cd743b..9acf4b47d4 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -46,9 +46,9 @@ <optional> <ref name="cpu"/> </optional> - <optional> + <zeroOrMore> <ref name="sysinfo"/> - </optional> + </zeroOrMore> <ref name="os"/> <ref name="clock"/> <ref name="resources"/> @@ -5506,68 +5506,93 @@ --> <define name="sysinfo"> <element name="sysinfo"> - <attribute name="type"> - <value>smbios</value> - </attribute> - <interleave> - <optional> - <element name="bios"> - <oneOrMore> - <element name="entry"> - <attribute name="name"> - <ref name="sysinfo-bios-name"/> - </attribute> - <ref name="sysinfo-value"/> + <choice> + <group> + <attribute name="type"> + <value>smbios</value> + </attribute> + <interleave> + <optional> + <element name="bios"> + <oneOrMore> + <element name="entry"> + <attribute name="name"> + <ref name="sysinfo-bios-name"/> + </attribute> + <ref name="sysinfo-value"/> + </element> + </oneOrMore> </element> - </oneOrMore> - </element> - </optional> - <optional> - <element name="system"> - <oneOrMore> - <element name="entry"> - <attribute name="name"> - <ref name="sysinfo-system-name"/> - </attribute> - <ref name="sysinfo-value"/> + </optional> + <optional> + <element name="system"> + <oneOrMore> + <element name="entry"> + <attribute name="name"> + <ref name="sysinfo-system-name"/> + </attribute> + <ref name="sysinfo-value"/> + </element> + </oneOrMore> </element> - </oneOrMore> - </element> - </optional> - <zeroOrMore> - <element name="baseBoard"> - <oneOrMore> - <element name="entry"> - <attribute name="name"> - <ref name="sysinfo-baseBoard-name"/> - </attribute> - <ref name="sysinfo-value"/> + </optional> + <zeroOrMore> + <element name="baseBoard"> + <oneOrMore> + <element name="entry"> + <attribute name="name"> + <ref name="sysinfo-baseBoard-name"/> + </attribute> + <ref name="sysinfo-value"/> + </element> + </oneOrMore> </element> - </oneOrMore> - </element> - </zeroOrMore> - <optional> - <element name="chassis"> - <oneOrMore> - <element name="entry"> - <attribute name="name"> - <ref name="sysinfo-chassis-name"/> - </attribute> - <ref name="sysinfo-value"/> + </zeroOrMore> + <optional> + <element name="chassis"> + <oneOrMore> + <element name="entry"> + <attribute name="name"> + <ref name="sysinfo-chassis-name"/> + </attribute> + <ref name="sysinfo-value"/> + </element> + </oneOrMore> </element> - </oneOrMore> - </element> - </optional> - <optional> - <element name="oemStrings"> - <oneOrMore> - <element name="entry"> - <ref name="sysinfo-value"/> + </optional> + <optional> + <element name="oemStrings"> + <oneOrMore> + <element name="entry"> + <ref name="sysinfo-value"/> + </element> + </oneOrMore> </element> - </oneOrMore> - </element> - </optional> - </interleave> + </optional> + </interleave> + </group> + <group> + <attribute name="type"> + <value>fwcfg</value> + </attribute> + <zeroOrMore> + <element name="entry"> + <attribute name="name"> + <data type="string"/> + </attribute> + <choice> + <attribute name="value"> + <data type="string"/> + </attribute> + <attribute name="file"> + <data type="string"/> + </attribute> + </choice> + <empty/> + </element> + </zeroOrMore> + </group> + </choice> </element> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 57a5b7befe..bed77f1dd7 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3551,7 +3551,9 @@ void virDomainDefFree(virDomainDefPtr def) virDomainNumaFree(def->numa); - virSysinfoDefFree(def->sysinfo); + for (i = 0; i < def->nsysinfo; i++) + virSysinfoDefFree(def->sysinfo[i]); + VIR_FREE(def->sysinfo); virDomainRedirFilterDefFree(def->redirfilter); @@ -15708,67 +15710,146 @@ virSysinfoChassisParseXML(xmlNodePtr node, } -static virSysinfoDefPtr -virSysinfoParseXML(xmlNodePtr node, - xmlXPathContextPtr ctxt, - unsigned char *domUUID, - bool uuid_generated) +static int +virSysinfoParseSMBIOSDef(virSysinfoDefPtr def, + xmlXPathContextPtr ctxt, + unsigned char *domUUID, + bool uuid_generated) { - VIR_XPATH_NODE_AUTORESTORE(ctxt); - virSysinfoDefPtr def; xmlNodePtr tmpnode; - g_autofree char *type = NULL; - - ctxt->node = node; - - if (!virXMLNodeNameEqual(node, "sysinfo")) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("XML does not contain expected 'sysinfo' element")); - return NULL; - } - - if (VIR_ALLOC(def) < 0) - return NULL; - - type = virXMLPropString(node, "type"); - if (type == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("sysinfo must contain a type attribute")); - goto error; - } - if ((def->type = virSysinfoTypeFromString(type)) < 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("unknown sysinfo type '%s'"), type); - goto error; - } /* Extract BIOS related metadata */ if ((tmpnode = virXPathNode("./bios[1]", ctxt)) != NULL) { if (virSysinfoBIOSParseXML(tmpnode, ctxt, &def->bios) < 0) - goto error; + return -1; } /* Extract system related metadata */ if ((tmpnode = virXPathNode("./system[1]", ctxt)) != NULL) { if (virSysinfoSystemParseXML(tmpnode, ctxt, &def->system, domUUID, uuid_generated) < 0) - goto error; + return -1; } /* Extract system base board metadata */ if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard, &def->nbaseBoard) < 0) - goto error; + return -1; /* Extract chassis related metadata */ if ((tmpnode = virXPathNode("./chassis[1]", ctxt)) != NULL) { if (virSysinfoChassisParseXML(tmpnode, ctxt, &def->chassis) < 0) - goto error; + return -1; } /* Extract system related metadata */ if ((tmpnode = virXPathNode("./oemStrings[1]", ctxt)) != NULL) { if (virSysinfoOEMStringsParseXML(tmpnode, ctxt, &def->oemStrings) < 0) + return -1; + } + + return 0; +} + + +static int +virSysinfoParseFWCfgDef(virSysinfoDefPtr def, + xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autofree xmlNodePtr *nodes = NULL; + int n; + size_t i; + + ctxt->node = node; + + if ((n = virXPathNodeSet("./entry", ctxt, &nodes)) < 0) + return -1; + + if (n == 0) + return 0; + + def->fw_cfgs = g_new0(virSysinfoFWCfgDef, n); + + for (i = 0; i < n; i++) { + g_autofree char *name = NULL; + g_autofree char *value = NULL; + g_autofree char *file = NULL; + + if (!(name = virXMLPropString(nodes[i], "name"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Firmware entry is missing 'name' attribute")); + return -1; + } + + value = virXMLPropString(nodes[i], "value"); + file = virXMLPropString(nodes[i], "file"); + + if (!value && !file) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Firmware entry must have either 'value' or " + "'file' attribute")); + return -1; + } + + def->fw_cfgs[i].name = g_steal_pointer(&name); + def->fw_cfgs[i].value = g_steal_pointer(&value); + def->fw_cfgs[i].file = g_steal_pointer(&file); + def->nfw_cfgs++; + } + + return 0; +} + + +static virSysinfoDefPtr +virSysinfoParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + unsigned char *domUUID, + bool uuid_generated) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + virSysinfoDefPtr def; + g_autofree char *typeStr = NULL; + int type; + + ctxt->node = node; + + if (!virXMLNodeNameEqual(node, "sysinfo")) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("XML does not contain expected 'sysinfo' element")); + return NULL; + } + + if (VIR_ALLOC(def) < 0) + return NULL; + + typeStr = virXMLPropString(node, "type"); + if (typeStr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("sysinfo must contain a type attribute")); + goto error; + } + if ((type = virSysinfoTypeFromString(typeStr)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown sysinfo type '%s'"), typeStr); + goto error; + } + def->type = type; + + switch (def->type) { + case VIR_SYSINFO_SMBIOS: + if (virSysinfoParseSMBIOSDef(def, ctxt, domUUID, uuid_generated) < 0) goto error; + break; + + case VIR_SYSINFO_FWCFG: + if (virSysinfoParseFWCfgDef(def, node, ctxt) < 0) + goto error; + break; + + case VIR_SYSINFO_LAST: + break; } return def; @@ -22173,6 +22254,7 @@ virDomainDefParseXML(xmlDocPtr xml, def->idmap.ngidmap = n; } + VIR_FREE(nodes); if ((def->idmap.uidmap && !def->idmap.gidmap) || (!def->idmap.uidmap && def->idmap.gidmap)) { @@ -22181,13 +22263,21 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; } - if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) { - def->sysinfo = virSysinfoParseXML(node, ctxt, - def->uuid, uuid_generated); + if ((n = virXPathNodeSet("./sysinfo", ctxt, &nodes)) < 0) + goto error; - if (def->sysinfo == NULL) + def->sysinfo = g_new0(virSysinfoDefPtr, n); + + for (i = 0; i < n; i++) { + virSysinfoDefPtr sysinfo = virSysinfoParseXML(nodes[i], ctxt, + def->uuid, uuid_generated); + + if (!sysinfo) goto error; + + def->sysinfo[def->nsysinfo++] = sysinfo; } + VIR_FREE(nodes); if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) { int mode; @@ -24072,8 +24162,16 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, if (!virCPUDefIsEqual(src->cpu, dst->cpu, true)) goto error; - if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo)) - goto error; + if (src->nsysinfo != dst->nsysinfo) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target domain count of sysinfo does not match source")); + goto error; + } + + for (i = 0; i < src->nsysinfo; i++) { + if (!virSysinfoIsEqual(src->sysinfo[i], dst->sysinfo[i])) + goto error; + } if (src->ndisks != dst->ndisks) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -29507,8 +29605,8 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, if (def->resource) virDomainResourceDefFormat(buf, def->resource); - if (def->sysinfo) - ignore_value(virSysinfoFormat(buf, def->sysinfo)); + for (i = 0; i < def->nsysinfo; i++) + virSysinfoFormat(buf, def->sysinfo[i]); if (def->os.bootloader) { virBufferEscapeString(buf, "<bootloader>%s</bootloader>\n", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e152c599ca..bda8fb6bce 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2624,13 +2624,15 @@ struct _virDomainDef { size_t npanics; virDomainPanicDefPtr *panics; + size_t nsysinfo; + virSysinfoDefPtr *sysinfo; + /* Only 1 */ virDomainWatchdogDefPtr watchdog; virDomainMemballoonDefPtr memballoon; virDomainNVRAMDefPtr nvram; virDomainTPMDefPtr tpm; virCPUDefPtr cpu; - virSysinfoDefPtr sysinfo; virDomainRedirFilterDefPtr redirfilter; virDomainIOMMUDefPtr iommu; virDomainVsockDefPtr vsock; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 419eca5675..6eb577a68b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5736,13 +5736,19 @@ qemuBuildSmbiosCommandLine(virCommandPtr cmd, /* Host and guest uuid must differ, by definition of UUID. */ skip_uuid = true; } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_SYSINFO) { - if (def->sysinfo == NULL) { + for (i = 0; i < def->nsysinfo; i++) { + if (def->sysinfo[i]->type == VIR_SYSINFO_SMBIOS) { + source = def->sysinfo[i]; + break; + } + } + + if (!source) { virReportError(VIR_ERR_XML_ERROR, _("Domain '%s' sysinfo are not available"), def->name); return -1; } - source = def->sysinfo; /* domain_conf guaranteed that system_uuid matches guest uuid. */ } if (source != NULL) { diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 41f4d1cff9..50e42610ca 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -43,6 +43,7 @@ VIR_LOG_INIT("util.sysinfo"); VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST, "smbios", + "fwcfg" ); static const char *sysinfoDmidecode = DMIDECODE; @@ -1436,6 +1437,42 @@ virSysinfoOEMStringsFormat(virBufferPtr buf, virSysinfoOEMStringsDefPtr def) virBufferAddLit(buf, "</oemStrings>\n"); } + +static void +virSysinfoFormatSMBIOS(virBufferPtr buf, + virSysinfoDefPtr def) +{ + virSysinfoBIOSFormat(buf, def->bios); + virSysinfoSystemFormat(buf, def->system); + virSysinfoBaseBoardFormat(buf, def->baseBoard, def->nbaseBoard); + virSysinfoChassisFormat(buf, def->chassis); + virSysinfoProcessorFormat(buf, def); + virSysinfoMemoryFormat(buf, def); + virSysinfoOEMStringsFormat(buf, def->oemStrings); +} + + +static void +virSysinfoFormatFWCfg(virBufferPtr buf, + virSysinfoDefPtr def) +{ + size_t i; + + for (i = 0; i < def->nfw_cfgs; i++) { + const virSysinfoFWCfgDef *f = &def->fw_cfgs[i]; + + virBufferAsprintf(buf, "<entry name='%s' ", f->name); + + if (f->value) + virBufferEscapeString(buf, "value='%s'", f->value); + else + virBufferEscapeString(buf, "file='%s'", f->file); + + virBufferAddLit(buf, "/>\n"); + } +} + + /** * virSysinfoFormat: * @buf: buffer to append output to (may use auto-indentation) @@ -1458,13 +1495,16 @@ virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) return -1; } - virSysinfoBIOSFormat(&childrenBuf, def->bios); - virSysinfoSystemFormat(&childrenBuf, def->system); - virSysinfoBaseBoardFormat(&childrenBuf, def->baseBoard, def->nbaseBoard); - virSysinfoChassisFormat(&childrenBuf, def->chassis); - virSysinfoProcessorFormat(&childrenBuf, def); - virSysinfoMemoryFormat(&childrenBuf, def); - virSysinfoOEMStringsFormat(&childrenBuf, def->oemStrings); + switch (def->type) { + case VIR_SYSINFO_SMBIOS: + virSysinfoFormatSMBIOS(&childrenBuf, def); + break; + case VIR_SYSINFO_FWCFG: + virSysinfoFormatFWCfg(&childrenBuf, def); + break; + case VIR_SYSINFO_LAST: + break; + } virBufferAsprintf(&attrBuf, " type='%s'", type); diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h index f1d280e1c9..6b25969a4b 100644 --- a/src/util/virsysinfo.h +++ b/src/util/virsysinfo.h @@ -27,6 +27,7 @@ typedef enum { VIR_SYSINFO_SMBIOS, + VIR_SYSINFO_FWCFG, VIR_SYSINFO_LAST } virSysinfoType; @@ -112,11 +113,20 @@ struct _virSysinfoOEMStringsDef { char **values; }; +typedef struct _virSysinfoFWCfgDef virSysinfoFWCfgDef; +typedef virSysinfoFWCfgDef *virSysinfoFWCfgDefPtr; +struct _virSysinfoFWCfgDef { + char *name; + char *value; + char *file; +}; + typedef struct _virSysinfoDef virSysinfoDef; typedef virSysinfoDef *virSysinfoDefPtr; struct _virSysinfoDef { - int type; + virSysinfoType type; + /* The following members are valid for type == VIR_SYSINFO_SMBIOS */ virSysinfoBIOSDefPtr bios; virSysinfoSystemDefPtr system; @@ -132,6 +142,10 @@ struct _virSysinfoDef { virSysinfoMemoryDefPtr memory; virSysinfoOEMStringsDefPtr oemStrings; + + /* The following members are valid for type == VIR_SYSINFO_FWCFG */ + size_t nfw_cfgs; + virSysinfoFWCfgDefPtr fw_cfgs; }; virSysinfoDefPtr virSysinfoRead(void); diff --git a/tests/qemuxml2argvdata/smbios-type-fwcfg.xml b/tests/qemuxml2argvdata/smbios-type-fwcfg.xml new file mode 100644 index 0000000000..2644833b21 --- /dev/null +++ b/tests/qemuxml2argvdata/smbios-type-fwcfg.xml @@ -0,0 +1,63 @@ +<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'>1</vcpu> + <sysinfo type='smbios'> + <bios> + <entry name='vendor'>LENOVO</entry> + <entry name='version'>6FET82WW (3.12 )</entry> + </bios> + <system> + <entry name='manufacturer'>Fedora</entry> + <entry name='product'>Virt-Manager</entry> + <entry name='version'>0.8.2-3.fc14</entry> + <entry name='serial'>32dfcb37-5af1-552b-357c-be8c3aa38310</entry> + <entry name='uuid'>c7a5fdbd-edaf-9455-926a-d65c16db1809</entry> + <entry name='sku'>1234567890</entry> + <entry name='family'>Red Hat</entry> + </system> + <baseBoard> + <entry name='manufacturer'>Lenovo</entry> + <entry name='product'>20BE0061MC</entry> + <entry name='version'>0B98401 Pro</entry> + <entry name='serial'>W1KS427111E</entry> + <entry name='location'>Not Available</entry> + </baseBoard> + </sysinfo> + <sysinfo type='fwcfg'> + <entry name='opt/com.example/name' value='example value'/> + <entry name='opt/com.coreos/config' file='/tmp/provision.ign'/> + </sysinfo> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + <smbios mode='sysinfo'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-i386</emulator> + <disk type='block' device='disk'> + <driver name='qemu' type='raw'/> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/smbios-type-fwcfg.xml b/tests/qemuxml2xmloutdata/smbios-type-fwcfg.xml new file mode 120000 index 0000000000..09a2682910 --- /dev/null +++ b/tests/qemuxml2xmloutdata/smbios-type-fwcfg.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/smbios-type-fwcfg.xml \ No newline at end of file diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index dcc7b29ded..157e686f2a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -1125,6 +1125,7 @@ mymain(void) DO_TEST("shmem-plain-doorbell", NONE); DO_TEST("smbios", NONE); DO_TEST("smbios-multiple-type2", NONE); + DO_TEST("smbios-type-fwcfg", NONE); DO_TEST_CAPS_LATEST("os-firmware-bios"); DO_TEST_CAPS_LATEST("os-firmware-efi"); -- 2.26.2