xl/libxl: Add ability to specify SMBIOS strings

hvm_xs_strings.h specifies xenstore entries which can be used to set or
override smbios strings.  hvmloader has support for reading them, but
xl/libxl support is not wired up.

Allow specifying the strings with the new xl.cfg option:
smbios=["bios_vendor=Xen Project","system_version=1.0"]

In terms of strings, the SMBIOS specification 3.5 says:
https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf
"""
Strings must be encoded as UTF-8 with no byte order mark (BOM). For
compatibility with older SMBIOS parsers, US-ASCII characters should be
used.  NOTE There is no limit on the length of each individual text
string. However, the length of the entire structure table (including all
strings) must be reported in the Structure Table Length field of the
32-bit Structure Table Entry Point (see 5.2.1) and/or the Structure
Table Maximum Size field of the 64-bit Structure Table Entry Point (see
5.2.2).
"""

The strings aren't checked for utf-8 or length.  hvmloader has a sanity
check on the overall length.

The libxl_smbios_type enum starts at 1 since otherwise the 0th key is
not printed in the json output.

Signed-off-by: Jason Andryuk <jandryuk@gmail.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
This commit is contained in:
Jason Andryuk authored and Andrew Cooper committed 2023-03-15 18:41:46 +00:00
1 parent d03246206c
commit 9aeb3a20c4
7 files changed
+232 -1

No files matched your search

+45
View File
@@ -2079,6 +2079,51 @@ number of vendor defined SMBIOS structures (type 128 - 255). Since SMBIOS
structures do not present their overall size, each entry in the file must be
preceded by a 32b integer indicating the size of the following structure.
=item B<smbios=[ "SMBIOS_SPEC_STRING", "SMBIOS_SPEC_STRING", ...]>
Specifies the SMBIOS values to be provided to the guest. These set or
override specific entries in the tables provided to the guest.
Each B<SMBIOS_SPEC_STRING> is a C<KEY=VALUE> string from the following list:
=over 4
=item B<bios_vendor=STRING>
=item B<bios_version=STRING>
=item B<system_manufacturer=STRING>
=item B<system_product_name=STRING>
=item B<system_version=STRING>
=item B<system_serial_number=STRING>
=item B<baseboard_manufacturer=STRING>
=item B<baseboard_product_name=STRING>
=item B<baseboard_version=STRING>
=item B<baseboard_serial_number=STRING>
=item B<baseboard_asset_tag=STRING>
=item B<baseboard_location_in_chassis=STRING>
=item B<enclosure_manufacturer=STRING>
=item B<enclosure_serial_number=STRING>
=item B<enclosure_asset_tag=STRING>
=item B<battery_manufacturer=STRING>
=item B<battery_device_name=STRING>
=back
=item B<ms_vm_genid="OPTION">
Provide a VM generation ID to the guest.
+51
View File
@@ -589,6 +589,38 @@ xc.build_id = C.CString(x.BuildId)}
return nil
}
// NewSmbios returns an instance of Smbios initialized with defaults.
func NewSmbios() (*Smbios, error) {
var (
x Smbios
xc C.libxl_smbios)
C.libxl_smbios_init(&xc)
defer C.libxl_smbios_dispose(&xc)
if err := x.fromC(&xc); err != nil {
return nil, err }
return &x, nil}
func (x *Smbios) fromC(xc *C.libxl_smbios) error {
x.Key = SmbiosType(xc.key)
x.Value = C.GoString(xc.value)
return nil}
func (x *Smbios) toC(xc *C.libxl_smbios) (err error){defer func(){
if err != nil{
C.libxl_smbios_dispose(xc)}
}()
xc.key = C.libxl_smbios_type(x.Key)
if x.Value != "" {
xc.value = C.CString(x.Value)}
return nil
}
// NewDomainCreateInfo returns an instance of DomainCreateInfo initialized with defaults.
func NewDomainCreateInfo() (*DomainCreateInfo, error) {
var (
@@ -1183,6 +1215,15 @@ return fmt.Errorf("converting field Altp2M: %v", err)
}
x.SystemFirmware = C.GoString(tmp.system_firmware)
x.SmbiosFirmware = C.GoString(tmp.smbios_firmware)
x.Smbios = nil
if n := int(tmp.num_smbios); n > 0 {
cSmbios := (*[1<<28]C.libxl_smbios)(unsafe.Pointer(tmp.smbios))[:n:n]
x.Smbios = make([]Smbios, n)
for i, v := range cSmbios {
if err := x.Smbios[i].fromC(&v); err != nil {
return fmt.Errorf("converting field Smbios: %v", err) }
}
}
x.AcpiFirmware = C.GoString(tmp.acpi_firmware)
x.Hdtype = Hdtype(tmp.hdtype)
if err := x.Nographic.fromC(&tmp.nographic);err != nil {
@@ -1495,6 +1536,16 @@ if tmp.SystemFirmware != "" {
hvm.system_firmware = C.CString(tmp.SystemFirmware)}
if tmp.SmbiosFirmware != "" {
hvm.smbios_firmware = C.CString(tmp.SmbiosFirmware)}
if numSmbios := len(tmp.Smbios); numSmbios > 0 {
hvm.smbios = (*C.libxl_smbios)(C.malloc(C.ulong(numSmbios)*C.sizeof_libxl_smbios))
hvm.num_smbios = C.int(numSmbios)
cSmbios := (*[1<<28]C.libxl_smbios)(unsafe.Pointer(hvm.smbios))[:numSmbios:numSmbios]
for i,v := range tmp.Smbios {
if err := v.toC(&cSmbios[i]); err != nil {
return fmt.Errorf("converting field Smbios: %v", err)
}
}
}
if tmp.AcpiFirmware != "" {
hvm.acpi_firmware = C.CString(tmp.AcpiFirmware)}
hvm.hdtype = C.libxl_hdtype(tmp.Hdtype)
+27
View File
@@ -392,6 +392,32 @@ Commandline string
BuildId string
}
type SmbiosType int
const(
SmbiosTypeBiosVendor SmbiosType = 1
SmbiosTypeBiosVersion SmbiosType = 2
SmbiosTypeSystemManufacturer SmbiosType = 3
SmbiosTypeSystemProductName SmbiosType = 4
SmbiosTypeSystemVersion SmbiosType = 5
SmbiosTypeSystemSerialNumber SmbiosType = 6
SmbiosTypeBaseboardManufacturer SmbiosType = 7
SmbiosTypeBaseboardProductName SmbiosType = 8
SmbiosTypeBaseboardVersion SmbiosType = 9
SmbiosTypeBaseboardSerialNumber SmbiosType = 10
SmbiosTypeBaseboardAssetTag SmbiosType = 11
SmbiosTypeBaseboardLocationInChassis SmbiosType = 12
SmbiosTypeEnclosureManufacturer SmbiosType = 13
SmbiosTypeEnclosureSerialNumber SmbiosType = 14
SmbiosTypeEnclosureAssetTag SmbiosType = 15
SmbiosTypeBatteryManufacturer SmbiosType = 16
SmbiosTypeBatteryDeviceName SmbiosType = 17
)
type Smbios struct {
Key SmbiosType
Value string
}
type DomainCreateInfo struct {
Type DomainType
Hap Defbool
@@ -572,6 +598,7 @@ NestedHvm Defbool
Altp2M Defbool
SystemFirmware string
SmbiosFirmware string
Smbios []Smbios
AcpiFirmware string
Hdtype Hdtype
Nographic Defbool
+5
View File
@@ -174,6 +174,11 @@
*/
#define LIBXL_HAVE_BUILDINFO_HVM_MS_VM_GENID 1
/*
* libxl_domain_build_info has the u.hvm.smbios field.
*/
#define LIBXL_HAVE_BUILDINFO_HVM_SMBIOS 1
/*
* LIBXL_HAVE_VCPUINFO_SOFT_AFFINITY indicates that a 'cpumap_soft'
* field (of libxl_bitmap type) is present in libxl_vcpuinfo,
+21
View File
@@ -773,6 +773,27 @@ static int hvm_build_set_xs_values(libxl__gc *gc,
goto err;
}
for (int i = 0; i < info->u.hvm.num_smbios; i++) {
char *p;
path = GCSPRINTF("/local/domain/%d/"HVM_XS_BIOS_STRINGS"/%s", domid,
libxl_smbios_type_to_string(info->u.hvm.smbios[i].key));
/* Convert libxl_smbios_type string to xenstore path that hvmloader
* will use, as defined by HVM_XS_*. That is convert the '_' to '-'. */
p = strrchr(path, '/');
for ( ; *p; p++) {
if (*p == '_')
*p = '-';
}
LOGD(DEBUG, domid, "Writing %s = \"%s\"", path,
info->u.hvm.smbios[i].value);
ret = libxl__xs_printf(gc, XBT_NULL, path, "%s",
info->u.hvm.smbios[i].value);
if (ret)
goto err;
}
/* Only one module can be passed. PVHv2 guests do not support this. */
if (dom->acpi_modules[0].guest_addr_out &&
info->type == LIBXL_DOMAIN_TYPE_HVM) {
+26
View File
@@ -423,6 +423,31 @@ libxl_version_info = Struct("version_info", [
("build_id", string),
], dir=DIR_OUT)
libxl_smbios_type = Enumeration("smbios_type", [
(1, "bios_vendor"),
(2, "bios_version"),
(3, "system_manufacturer"),
(4, "system_product_name"),
(5, "system_version"),
(6, "system_serial_number"),
(7, "baseboard_manufacturer"),
(8, "baseboard_product_name"),
(9, "baseboard_version"),
(10, "baseboard_serial_number"),
(11, "baseboard_asset_tag"),
(12, "baseboard_location_in_chassis"),
(13, "enclosure_manufacturer"),
(14, "enclosure_serial_number"),
(15, "enclosure_asset_tag"),
(16, "battery_manufacturer"),
(17, "battery_device_name"),
])
libxl_smbios = Struct("smbios", [
("key", libxl_smbios_type),
("value", string),
], dir=DIR_IN)
libxl_domain_create_info = Struct("domain_create_info",[
("type", libxl_domain_type),
("hap", libxl_defbool),
@@ -609,6 +634,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
("altp2m", libxl_defbool),
("system_firmware", string),
("smbios_firmware", string),
("smbios", Array(libxl_smbios, "num_smbios")),
("acpi_firmware", string),
("hdtype", libxl_hdtype),
("nographic", libxl_defbool),
+57 -1
View File
@@ -1297,8 +1297,9 @@ void parse_config_data(const char *config_source,
XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
*usbctrls, *usbdevs, *p9devs, *vdispls, *pvcallsifs_devs;
XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
*mca_caps;
*mca_caps, *smbios;
int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
int num_smbios;
int pci_power_mgmt = 0;
int pci_msitranslate = 0;
int pci_permissive = 0;
@@ -1860,6 +1861,61 @@ void parse_config_data(const char *config_source,
xlu_cfg_replace_string(config, "acpi_firmware",
&b_info->u.hvm.acpi_firmware, 0);
switch (xlu_cfg_get_list(config, "smbios", &smbios, &num_smbios, 0))
{
case 0: /* Success */
b_info->u.hvm.num_smbios = num_smbios;
b_info->u.hvm.smbios = xcalloc(num_smbios, sizeof(libxl_smbios));
for (i = 0; i < num_smbios; i++) {
libxl_smbios_type type;
char *option;
char *value;
buf = xlu_cfg_get_listitem(smbios, i);
if (!buf) {
fprintf(stderr,
"xl: Unable to get element #%d in smbios list\n",
i);
exit(EXIT_FAILURE);
}
option = xstrdup(buf);
value = strchr(option, '=');
if (value == NULL) {
fprintf(stderr, "xl: failed to split \"%s\" at '='\n",
option);
exit(EXIT_FAILURE);
}
*value = '\0';
value++;
if (*value == '\0') {
fprintf(stderr,
"xl: empty value not allowed for smbios \"%s=\"\n",
option);
exit(EXIT_FAILURE);
}
e = libxl_smbios_type_from_string(option, &type);
if (e) {
fprintf(stderr, "xl: unknown smbios type '%s'\n", option);
exit(EXIT_FAILURE);
}
b_info->u.hvm.smbios[i].key = type;
b_info->u.hvm.smbios[i].value = xstrdup(value);
free(option);
}
break;
case ESRCH: /* Option not present */
break;
default:
fprintf(stderr,"xl: Unable to parse smbios options.\n");
exit(EXIT_FAILURE);
}
if (!xlu_cfg_get_string(config, "ms_vm_genid", &buf, 0)) {
if (!strcmp(buf, "generate")) {
e = libxl_ms_vm_genid_generate(ctx, &b_info->u.hvm.ms_vm_genid);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.