[PATCH v2 3/8] conf: Add firmware blob configuration

Michal Privoznik mprivozn at redhat.com
Thu Jun 4 18:44:04 UTC 2020


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 at redhat.com>
---
 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




More information about the libvir-list mailing list