[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 1/2] smbios: Add type 41 structure (Onboard Devices
From: |
Ivan Mironov |
Subject: |
[Qemu-devel] [PATCH 1/2] smbios: Add type 41 structure (Onboard Devices Extended Information). |
Date: |
Tue, 19 Nov 2013 20:48:28 +0400 |
Signed-off-by: Ivan Mironov <address@hidden>
---
hw/i386/smbios.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++-
include/hw/i386/smbios.h | 11 +++
qemu-options.hx | 42 ++++++++-
3 files changed, 268 insertions(+), 4 deletions(-)
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index d3f1ee6..c5fccba 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -19,6 +19,7 @@
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "hw/i386/smbios.h"
+#include "hw/pci/pci.h"
#include "hw/loader.h"
/*
@@ -66,6 +67,48 @@ static struct {
/* uuid is in qemu_uuid[] */
} type1;
+#define ONBOARD_DEV_TYPE_MIN 0x01
+#define ONBOARD_DEV_TYPE_MAX 0x0A
+#define ONBOARD_DEV_TYPE_NUM \
+ (ONBOARD_DEV_TYPE_MAX - ONBOARD_DEV_TYPE_MIN + 1)
+
+static const struct {
+ const char *type_str;
+ uint8_t type_num;
+} onboard_dev_type_str[ONBOARD_DEV_TYPE_NUM] = {
+ {
+ .type_str = "other",
+ .type_num = 0x01,
+ },{
+ .type_str = "unknown",
+ .type_num = 0x02,
+ },{
+ .type_str = "video",
+ .type_num = 0x03,
+ },{
+ .type_str = "scsi",
+ .type_num = 0x04,
+ },{
+ .type_str = "ethernet",
+ .type_num = 0x05,
+ },{
+ .type_str = "token-ring",
+ .type_num = 0x06,
+ },{
+ .type_str = "sound",
+ .type_num = 0x07,
+ },{
+ .type_str = "pata",
+ .type_num = 0x08,
+ },{
+ .type_str = "sata",
+ .type_num = 0x09,
+ },{
+ .type_str = "sas",
+ .type_num = 0x0a,
+ }
+};
+
static QemuOptsList qemu_smbios_opts = {
.name = "smbios",
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
@@ -149,6 +192,35 @@ static const QemuOptDesc qemu_smbios_type1_opts[] = {
{ /* end of list */ }
};
+static const QemuOptDesc qemu_smbios_type41_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "designation",
+ .type = QEMU_OPT_STRING,
+ .help = "reference designation",
+ },{
+ .name = "status",
+ .type = QEMU_OPT_BOOL,
+ .help = "device status",
+ },{
+ .name = "device-type",
+ .type = QEMU_OPT_STRING,
+ .help = "device type",
+ },{
+ .name = "instance",
+ .type = QEMU_OPT_NUMBER,
+ .help = "device type instance",
+ },{
+ .name = "address",
+ .type = QEMU_OPT_STRING,
+ .help = "pci bus address",
+ },
+ { /* end of list */ }
+};
+
static void smbios_register_config(void)
{
qemu_add_opts(&qemu_smbios_opts);
@@ -217,6 +289,11 @@ static void smbios_maybe_add_str(int type, int offset,
const char *data)
}
}
+static void smbios_add_fields_set_end_marker(int type)
+{
+ smbios_add_field(type, 0, NULL, 0);
+}
+
static void smbios_build_type_0_fields(void)
{
smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
@@ -277,6 +354,119 @@ static void save_opt(const char **dest, QemuOpts *opts,
const char *name)
}
}
+static void smbios_check_onboard_device_instance(int type, int instance)
+{
+ static uint8_t instances[ONBOARD_DEV_TYPE_NUM][UINT8_MAX / 8];
+ uint8_t *type_instances = instances[type];
+
+ if (type_instances[instance / 8] & (1 << (instance % 8))) {
+ error_report("instance %d is not unique within device-type %d",
+ instance, type);
+ exit(1);
+ }
+ type_instances[instance / 8] |= (uint8_t)(1 << (instance % 8));
+}
+
+static void smbios_entry_add_type_41(QemuOpts *opts)
+{
+ const char *designation;
+ bool dev_status;
+ const char *dev_type_str;
+ unsigned long dev_type = 0x02 /* Unknown */;
+ uint64_t dev_instance;
+ const char *address;
+ int seg, bus;
+ unsigned int dev, func;
+
+ /* Reference Designation */
+ designation = qemu_opt_get(opts, "designation");
+ smbios_maybe_add_str(41,
+ offsetof(struct smbios_type_41, reference_designation_str),
+ designation);
+
+ /* Device Type */
+ dev_status = qemu_opt_get_bool(opts, "status", true /* Enabled */);
+ dev_type_str = qemu_opt_get(opts, "device-type");
+ if (dev_type_str) {
+ char *endptr;
+ dev_type = strtoul(dev_type_str, &endptr, 0);
+ if (*dev_type_str && !*endptr) {
+ /* Got number. */
+ if (dev_type < ONBOARD_DEV_TYPE_MIN) {
+ error_report("device-type is < %d", ONBOARD_DEV_TYPE_MIN);
+ exit(1);
+ }
+ if (dev_type > ONBOARD_DEV_TYPE_MAX) {
+ error_report("device-type is > %d", ONBOARD_DEV_TYPE_MAX);
+ exit(1);
+ }
+ } else {
+ /* Got string. */
+ unsigned int i;
+ dev_type = 0;
+ for (i = 0; i < ONBOARD_DEV_TYPE_NUM; i++) {
+ if (!strcmp(dev_type_str, onboard_dev_type_str[i].type_str)) {
+ dev_type = onboard_dev_type_str[i].type_num;
+ break;
+ }
+ }
+ if (!dev_type) {
+ error_report("unknown device-type");
+ exit(1);
+ }
+ }
+ }
+ smbios_add_field(41,
+ offsetof(struct smbios_type_41, device_type),
+ &(uint8_t){ ((dev_status ? 1 : 0) << 7) | dev_type },
+ sizeof(uint8_t));
+
+ /* Device Type Instance */
+ dev_instance = qemu_opt_get_number(opts, "instance", UINT64_MAX);
+ if (dev_instance == UINT64_MAX) {
+ error_report("You should specify instance");
+ exit(1);
+ }
+ if (dev_instance < 1) {
+ error_report("instance is < 1");
+ exit(1);
+ }
+ if (dev_instance > UINT8_MAX) {
+ error_report("instance is > %d", UINT8_MAX);
+ exit(1);
+ }
+ smbios_check_onboard_device_instance(dev_type, dev_instance);
+ smbios_add_field(41,
+ offsetof(struct smbios_type_41, device_type_instance),
+ &(uint8_t){ dev_instance },
+ sizeof(uint8_t));
+
+ /* Segment Group Number, Bus Number and Device/Function Number */
+ address = qemu_opt_get(opts, "address");
+ if (!address) {
+ error_report("You should specify address");
+ exit(1);
+ }
+ if (pci_parse_devaddr(address, &seg, &bus, &dev, &func) < 0) {
+ error_report("Invalid address");
+ exit(1);
+ }
+ smbios_add_field(41,
+ offsetof(struct smbios_type_41, segment_group_number),
+ &(uint16_t){ cpu_to_le16(seg) },
+ sizeof(uint16_t));
+ smbios_add_field(41,
+ offsetof(struct smbios_type_41, bus_number),
+ &(uint8_t){ bus },
+ sizeof(uint8_t));
+ smbios_add_field(41,
+ offsetof(struct smbios_type_41, device_function_number),
+ &(uint8_t){ (dev << 3) | func },
+ sizeof(uint8_t));
+
+ smbios_add_fields_set_end_marker(41);
+}
+
void smbios_entry_add(QemuOpts *opts)
{
Error *local_err = NULL;
@@ -319,8 +509,27 @@ void smbios_entry_add(QemuOpts *opts)
header = (struct smbios_structure_header *)(table->data);
smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
- if (header->type == 4) {
+ switch (header->type) {
+ case 4:
smbios_type4_count++;
+ break;
+ case 41:
+ if (size != sizeof(struct smbios_type_41)) {
+ error_report("Failed to load SMBIOS file %s: invalid type 41 "
+ "table", val);
+ exit(1);
+ }
+
+ {
+ uint8_t dev_type = table->data
+ [offsetof(struct smbios_type_41, device_type)];
+ uint8_t dev_instance = table->data
+ [offsetof(struct smbios_type_41,
device_type_instance)];
+ smbios_check_onboard_device_instance(dev_type, dev_instance);
+ }
+ break;
+ default:
+ break;
}
smbios_entries_len += sizeof(*table) + size;
@@ -377,6 +586,14 @@ void smbios_entry_add(QemuOpts *opts)
qemu_uuid_set = true;
}
return;
+ case 41:
+ qemu_opts_validate(opts, qemu_smbios_type41_opts, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
+ smbios_entry_add_type_41(opts);
+ return;
default:
error_report("Don't know how to build fields for SMBIOS type %ld",
type);
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
index b08ec71..a57ffc9 100644
--- a/include/hw/i386/smbios.h
+++ b/include/hw/i386/smbios.h
@@ -155,6 +155,17 @@ struct smbios_type_32 {
uint8_t boot_status;
} QEMU_PACKED;
+/* SMBIOS type 41 - Onboard Devices Extended Information */
+struct smbios_type_41 {
+ struct smbios_structure_header header;
+ uint8_t reference_designation_str;
+ uint8_t device_type;
+ uint8_t device_type_instance;
+ uint16_t segment_group_number;
+ uint8_t bus_number;
+ uint8_t device_function_number;
+} QEMU_PACKED;
+
/* SMBIOS type 127 -- End-of-table */
struct smbios_type_127 {
struct smbios_structure_header header;
diff --git a/qemu-options.hx b/qemu-options.hx
index 5dc8b75..a3b4b78 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -154,8 +154,8 @@ Set default value of @var{driver}'s property @var{prop} to
@var{value}, e.g.:
qemu-system-i386 -global ide-drive.physical_block_size=4096 -drive
file=file,if=ide,index=0,media=disk
@end example
-In particular, you can use this to set driver properties for devices which are
-created automatically by the machine model. To create a device which is not
+In particular, you can use this to set driver properties for devices which are
+created automatically by the machine model. To create a device which is not
created automatically and set properties on it, use address@hidden
ETEXI
@@ -1320,7 +1320,10 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
" specify SMBIOS type 0 fields\n"
"-smbios
type=1[,manufacturer=str][,product=str][,version=str][,serial=str]\n"
" [,uuid=uuid][,sku=str][,family=str]\n"
- " specify SMBIOS type 1 fields\n", QEMU_ARCH_I386)
+ " specify SMBIOS type 1 fields\n"
+ "-smbios type=41,address=str,instance=n[,designation=str]\n"
+ " [,status=on|off][,device-type=str|n]\n"
+ " add SMBIOS type 41 fields (Onboard Devices Extended
Information)\n" , QEMU_ARCH_I386)
STEXI
@item -smbios address@hidden
@findex -smbios
@@ -1331,6 +1334,39 @@ Specify SMBIOS type 0 fields
@item -smbios type=1[,address@hidden,address@hidden
[,address@hidden,address@hidden,address@hidden,address@hidden [,address@hidden
Specify SMBIOS type 1 fields
+
address@hidden -smbios
type=41,address@hidden,address@hidden,address@hidden,status=on|off][,address@hidden|n}]
+Add SMBIOS type 41 fields (Onboard Devices Extended Information). Could be
+specified multiple times for different devices. Mandatory options are
address@hidden in form "[[<domain>:]<bus>:]<slot>.<func>" and
address@hidden number. @option{instance} shoud be in range [1, 255] and
+should be unique within specified @option{device-type}. @option{designation} is
+an optional string that somehow designates device. @option{status} is a device
+status and is "on" by default. @option{device-type} could be specified in
+numerical form or as string alias. Supported device types:
address@hidden
+n | string | description
+------------------------------------
+1 | other | Other
+2 | unknown | Unknown (default)
+3 | video | Video
+4 | scsi | SCSI Controller
+5 | ethernet | Ethernet
+6 | token-ring | Token Ring
+7 | sound | Sound
+8 | pata | PATA Controller
+9 | sata | SATA Controller
+10 | sas | SAS Controller
address@hidden example
+This option could be used in conjunction with biosdevname utility in linux
guest
+system to provide consistent network device naming. Usage example:
address@hidden
+qemu-i386 \
+-netdev user,id=hostnet0 \
+-device e1000,netdev=hostnet0,id=net0,bus=pci.0,addr=0x1f \
+-smbios type=41,address=00:1f.0,instance=1,designation="NIC
1",device-type=ethernet \
+< ... other qemu options ... >
address@hidden example
ETEXI
STEXI
--
1.8.4.1