qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2 1/2] smbios: Add type 41 structure (Onboard Devic


From: Ivan Mironov
Subject: [Qemu-devel] [PATCH v2 1/2] smbios: Add type 41 structure (Onboard Devices Extended Information).
Date: Wed, 20 Nov 2013 03:21:21 +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..355beb9 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 - ONBOARD_DEV_TYPE_MIN];
+
+    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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]