<entry name='product'>Virt-Manager</entry>
<entry name='version'>0.9.4</entry>
</system>
+ <baseBoard>
+ <entry name='manufacturer'>LENOVO</entry>
+ <entry name='product'>20BE0061MC</entry>
+ <entry name='version'>0B98401 Pro</entry>
+ <entry name='serial'>W1KS427111E</entry>
+ </baseBoard>
</sysinfo>
...</pre>
<dt><code>family</code></dt>
<dd>Identify the family a particular computer belongs to.</dd>
</dl>
- NB: Incorrectly supplied entries in either the <code>bios</code>
- or <code>system</code> blocks will be ignored without error.
- Other than <code>uuid</code> validation and <code>date</code>
- format checking, all values are passed as strings to the
- hypervisor driver.
+ </dd>
+ <dt><code>baseBoard</code></dt>
+ <dd>
+ This is block 2 of SMBIOS. This element can be repeated multiple
+ times to describe all the base boards; however, not all
+ hypervisors necessarily support the repetition. The element can
+ have the following children:
+ <dl>
+ <dt><code>manufacturer</code></dt>
+ <dd>Manufacturer of BIOS</dd>
+ <dt><code>product</code></dt>
+ <dd>Product Name</dd>
+ <dt><code>version</code></dt>
+ <dd>Version of the product</dd>
+ <dt><code>serial</code></dt>
+ <dd>Serial number</dd>
+ <dt><code>asset</code></dt>
+ <dd>Asset tag</dd>
+ <dt><code>location</code></dt>
+ <dd>Location in chassis</dd>
+ </dl>
+ NB: Incorrectly supplied entries for the
+ <code>bios</code>, <code>system</code> or <code>baseBoard</code>
+ blocks will be ignored without error. Other than <code>uuid</code>
+ validation and <code>date</code> format checking, all values are
+ passed as strings to the hypervisor driver.
</dd>
</dl>
</dd>
</oneOrMore>
</element>
</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>
+ </zeroOrMore>
</interleave>
</element>
</define>
</choice>
</define>
+ <define name="sysinfo-baseBoard-name">
+ <choice>
+ <value>manufacturer</value>
+ <value>product</value>
+ <value>version</value>
+ <value>serial</value>
+ <value>asset</value>
+ <value>location</value>
+ </choice>
+ </define>
+
<define name="sysinfo-value">
<data type="string">
<param name='pattern'>[a-zA-Z0-9/\-_\. \(\)]+</param>
return ret;
}
+static int
+virSysinfoBaseBoardParseXML(xmlXPathContextPtr ctxt,
+ virSysinfoBaseBoardDefPtr *baseBoard,
+ size_t *nbaseBoard)
+{
+ int ret = -1;
+ virSysinfoBaseBoardDefPtr boards = NULL;
+ size_t i, nboards = 0;
+ xmlNodePtr *nodes = NULL, oldnode = ctxt->node;
+ int n;
+
+ if ((n = virXPathNodeSet("./baseBoard", ctxt, &nodes)) < 0)
+ return ret;
+
+ if (n && VIR_ALLOC_N(boards, n) < 0)
+ goto cleanup;
+
+ for (i = 0; i < n; i++) {
+ virSysinfoBaseBoardDefPtr def = boards + nboards;
+
+ ctxt->node = nodes[i];
+
+ def->manufacturer =
+ virXPathString("string(entry[@name='manufacturer'])", ctxt);
+ def->product =
+ virXPathString("string(entry[@name='product'])", ctxt);
+ def->version =
+ virXPathString("string(entry[@name='version'])", ctxt);
+ def->serial =
+ virXPathString("string(entry[@name='serial'])", ctxt);
+ def->asset =
+ virXPathString("string(entry[@name='asset'])", ctxt);
+ def->location =
+ virXPathString("string(entry[@name='location'])", ctxt);
+
+ if (!def->manufacturer && !def->product && !def->version &&
+ !def->serial && !def->asset && !def->location) {
+ /* nada */
+ } else {
+ nboards++;
+ }
+ }
+
+ *baseBoard = boards;
+ *nbaseBoard = nboards;
+ boards = NULL;
+ nboards = 0;
+ ret = 0;
+ cleanup:
+ VIR_FREE(boards);
+ VIR_FREE(nodes);
+ ctxt->node = oldnode;
+ return ret;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
ctxt->node = oldnode;
}
+ /* Extract system base board metadata */
+ if (virSysinfoBaseBoardParseXML(ctxt, &def->baseBoard, &def->nbaseBoard) < 0)
+ goto error;
+
cleanup:
VIR_FREE(type);
return def;
# util/virsysinfo.h
+virSysinfoBaseBoardDefClear;
virSysinfoBIOSDefFree;
virSysinfoDefFree;
virSysinfoFormat;
return NULL;
}
+static char *qemuBuildSmbiosBaseBoardStr(virSysinfoBaseBoardDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (!def)
+ return NULL;
+
+ virBufferAddLit(&buf, "type=2");
+
+ /* 2:Manufacturer */
+ if (def->manufacturer)
+ virBufferAsprintf(&buf, ",manufacturer=%s",
+ def->manufacturer);
+ /* 2:Product Name */
+ if (def->product)
+ virBufferAsprintf(&buf, ",product=%s", def->product);
+ /* 2:Version */
+ if (def->version)
+ virBufferAsprintf(&buf, ",version=%s", def->version);
+ /* 2:Serial Number */
+ if (def->serial)
+ virBufferAsprintf(&buf, ",serial=%s", def->serial);
+ /* 2:Asset Tag */
+ if (def->asset)
+ virBufferAsprintf(&buf, ",asset=%s", def->asset);
+ /* 2:Location */
+ if (def->location)
+ virBufferAsprintf(&buf, ",location=%s", def->location);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
static char *
qemuBuildClockArgStr(virDomainClockDefPtr def)
{
virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
VIR_FREE(smbioscmd);
}
+
+ if (source->nbaseBoard > 1) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("qemu does not support more than "
+ "one entry to Type 2 in SMBIOS table"));
+ goto error;
+ }
+
+ for (i = 0; i < source->nbaseBoard; i++) {
+ if (!(smbioscmd = qemuBuildSmbiosBaseBoardStr(source->baseBoard + i)))
+ goto error;
+
+ virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
+ VIR_FREE(smbioscmd);
+ }
}
}
VIR_FREE(def);
}
+void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def)
+{
+ if (def == NULL)
+ return;
+
+ VIR_FREE(def->manufacturer);
+ VIR_FREE(def->product);
+ VIR_FREE(def->version);
+ VIR_FREE(def->serial);
+ VIR_FREE(def->asset);
+ VIR_FREE(def->location);
+}
/**
* virSysinfoDefFree:
virSysinfoBIOSDefFree(def->bios);
virSysinfoSystemDefFree(def->system);
+ for (i = 0; i < def->nbaseBoard; i++)
+ virSysinfoBaseBoardDefClear(def->baseBoard + i);
+ VIR_FREE(def->baseBoard);
+
for (i = 0; i < def->nprocessor; i++) {
VIR_FREE(def->processor[i].processor_socket_destination);
VIR_FREE(def->processor[i].processor_type);
return ret;
}
+static int
+virSysinfoParseBaseBoard(const char *base,
+ virSysinfoBaseBoardDefPtr *baseBoard,
+ size_t *nbaseBoard)
+{
+ int ret = -1;
+ const char *cur, *eol = NULL;
+ virSysinfoBaseBoardDefPtr boards = NULL;
+ size_t nboards = 0;
+ char *board_type = NULL;
+
+ while (base && (cur = strstr(base, "Base Board Information"))) {
+ virSysinfoBaseBoardDefPtr def;
+
+ if (VIR_EXPAND_N(boards, nboards, 1) < 0)
+ goto cleanup;
+
+ def = &boards[nboards - 1];
+
+ base = cur + 22;
+ if ((cur = strstr(base, "Manufacturer: ")) != NULL) {
+ cur += 14;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->manufacturer, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Product Name: ")) != NULL) {
+ cur += 14;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->product, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Version: ")) != NULL) {
+ cur += 9;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->version, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Serial Number: ")) != NULL) {
+ cur += 15;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->serial, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Asset Tag: ")) != NULL) {
+ cur += 11;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->asset, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+ if ((cur = strstr(base, "Location In Chassis: ")) != NULL) {
+ cur += 21;
+ eol = strchr(cur, '\n');
+ if (eol && VIR_STRNDUP(def->location, cur, eol - cur) < 0)
+ goto cleanup;
+ }
+
+ if (!def->manufacturer && !def->product && !def->version &&
+ !def->serial && !def->asset && !def->location)
+ nboards--;
+ }
+
+ /* This is safe, as we can be only shrinking the memory */
+ ignore_value(VIR_REALLOC_N(boards, nboards));
+
+ *baseBoard = boards;
+ *nbaseBoard = nboards;
+ boards = NULL;
+ nboards = 0;
+ ret = 0;
+ cleanup:
+ while (nboards--)
+ virSysinfoBaseBoardDefClear(&boards[nboards]);
+ VIR_FREE(boards);
+ VIR_FREE(board_type);
+ return ret;
+}
+
static int
virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret)
{
return NULL;
}
- cmd = virCommandNewArgList(path, "-q", "-t", "0,1,4,17", NULL);
+ cmd = virCommandNewArgList(path, "-q", "-t", "0,1,2,4,17", NULL);
VIR_FREE(path);
virCommandSetOutputBuffer(cmd, &outbuf);
if (virCommandRun(cmd, NULL) < 0)
if (virSysinfoParseSystem(outbuf, &ret->system) < 0)
goto error;
+ if (virSysinfoParseBaseBoard(outbuf, &ret->baseBoard, &ret->nbaseBoard) < 0)
+ goto error;
+
ret->nprocessor = 0;
ret->processor = NULL;
if (virSysinfoParseProcessor(outbuf, ret) < 0)
virBufferAddLit(buf, "</system>\n");
}
+static void
+virSysinfoBaseBoardFormat(virBufferPtr buf,
+ virSysinfoBaseBoardDefPtr baseBoard,
+ size_t nbaseBoard)
+{
+ virSysinfoBaseBoardDefPtr def;
+ size_t i;
+
+ for (i = 0; i < nbaseBoard; i++) {
+ def = baseBoard + i;
+
+ virBufferAddLit(buf, "<baseBoard>\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n",
+ def->manufacturer);
+ virBufferEscapeString(buf, "<entry name='product'>%s</entry>\n",
+ def->product);
+ virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n",
+ def->version);
+ virBufferEscapeString(buf, "<entry name='serial'>%s</entry>\n",
+ def->serial);
+ virBufferEscapeString(buf, "<entry name='asset'>%s</entry>\n",
+ def->asset);
+ virBufferEscapeString(buf, "<entry name='location'>%s</entry>\n",
+ def->location);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</baseBoard>\n");
+ }
+}
+
static void
virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def)
{
virSysinfoBIOSFormat(&childrenBuf, def->bios);
virSysinfoSystemFormat(&childrenBuf, def->system);
+ virSysinfoBaseBoardFormat(&childrenBuf, def->baseBoard, def->nbaseBoard);
virSysinfoProcessorFormat(&childrenBuf, def);
virSysinfoMemoryFormat(&childrenBuf, def);
return identical;
}
+static bool
+virSysinfoBaseBoardIsEqual(virSysinfoBaseBoardDefPtr src,
+ virSysinfoBaseBoardDefPtr dst)
+{
+ bool identical = false;
+
+ if (!src && !dst)
+ return true;
+
+ if ((src && !dst) || (!src && dst)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Target base board does not match source"));
+ goto cleanup;
+ }
+
+ CHECK_FIELD(manufacturer, "base board vendor");
+ CHECK_FIELD(product, "base board product");
+ CHECK_FIELD(version, "base board version");
+ CHECK_FIELD(serial, "base board serial");
+ CHECK_FIELD(asset, "base board asset");
+ CHECK_FIELD(location, "base board location");
+
+ identical = true;
+ cleanup:
+ return identical;
+}
+
#undef CHECK_FIELD
bool virSysinfoIsEqual(virSysinfoDefPtr src,
virSysinfoDefPtr dst)
{
bool identical = false;
+ size_t i;
if (!src && !dst)
return true;
if (!virSysinfoSystemIsEqual(src->system, dst->system))
goto cleanup;
+ if (src->nbaseBoard != dst->nbaseBoard) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target sysinfo base board count '%zu' does not match source '%zu'"),
+ dst->nbaseBoard, src->nbaseBoard);
+ goto cleanup;
+ }
+
+ for (i = 0; i < src->nbaseBoard; i++)
+ if (!virSysinfoBaseBoardIsEqual(src->baseBoard + i,
+ dst->baseBoard + i))
+ goto cleanup;
+
identical = true;
cleanup:
char *family;
};
+typedef struct _virSysinfoBaseBoardDef virSysinfoBaseBoardDef;
+typedef virSysinfoBaseBoardDef *virSysinfoBaseBoardDefPtr;
+struct _virSysinfoBaseBoardDef {
+ char *manufacturer;
+ char *product;
+ char *version;
+ char *serial;
+ char *asset;
+ char *location;
+ /* XXX board type */
+};
+
typedef struct _virSysinfoDef virSysinfoDef;
typedef virSysinfoDef *virSysinfoDefPtr;
struct _virSysinfoDef {
virSysinfoBIOSDefPtr bios;
virSysinfoSystemDefPtr system;
+ size_t nbaseBoard;
+ virSysinfoBaseBoardDefPtr baseBoard;
+
size_t nprocessor;
virSysinfoProcessorDefPtr processor;
void virSysinfoBIOSDefFree(virSysinfoBIOSDefPtr def);
void virSysinfoSystemDefFree(virSysinfoSystemDefPtr def);
+void virSysinfoBaseBoardDefClear(virSysinfoBaseBoardDefPtr def);
void virSysinfoDefFree(virSysinfoDefPtr def);
int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def)
--- /dev/null
+<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'>Hewlett-Packard</entry>
+ <entry name='product'>0B4Ch</entry>
+ <entry name='version'>D</entry>
+ <entry name='serial'>CZC1065993</entry>
+ <entry name='asset'>CZC1065993</entry>
+ <entry name='location'>Upside down</entry>
+ </baseBoard>
+ <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>
+ <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</emulator>
+ <disk type='block' device='disk'>
+ <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'/>
+ <controller type='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
-smbios 'type=1,manufacturer=Fedora,product=Virt-Manager,version=0.8.2-3.fc14,\
serial=32dfcb37-5af1-552b-357c-be8c3aa38310,\
uuid=c7a5fdbd-edaf-9455-926a-d65c16db1809,sku=1234567890,family=Red Hat' \
+-smbios 'type=2,manufacturer=Hewlett-Packard,product=0B4Ch,version=D,\
+serial=CZC1065993,asset=CZC1065993,location=Upside down' \
-nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \
/dev/HostVG/QEMUGuest1 -net none -serial none -parallel none
<entry name='sku'>1234567890</entry>
<entry name='family'>Red Hat</entry>
</system>
+ <baseBoard>
+ <entry name='manufacturer'>Hewlett-Packard</entry>
+ <entry name='product'>0B4Ch</entry>
+ <entry name='version'>D</entry>
+ <entry name='serial'>CZC1065993</entry>
+ <entry name='asset'>CZC1065993</entry>
+ <entry name='location'>Upside down</entry>
+ </baseBoard>
</sysinfo>
<os>
<type arch='i686' machine='pc'>hvm</type>
DO_TEST_DIFFERENT("tap-vhost-incorrect");
DO_TEST("shmem");
DO_TEST("smbios");
+ DO_TEST("smbios-multiple-type2");
DO_TEST("aarch64-aavmf-virtio-mmio");
DO_TEST("memory-hotplug");