qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH v2 2/2] smbios: Allow device ID instead of PCI addre


From: Ivan Mironov
Subject: [Qemu-devel] [PATCH v2 2/2] smbios: Allow device ID instead of PCI address for type 41.
Date: Wed, 20 Nov 2013 03:21:22 +0400

Signed-off-by: Ivan Mironov <address@hidden>
---
 hw/i386/pc.c             |  12 +++++
 hw/i386/smbios.c         | 129 +++++++++++++++++++++++++++++++++++++++--------
 include/hw/i386/smbios.h |   1 +
 qemu-options.hx          |   8 ++-
 4 files changed, 128 insertions(+), 22 deletions(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 12c436e..70d15b3 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -619,6 +619,14 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
     return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
 }
 
+static void bochs_bios_machine_done(Notifier *notifier, void *data)
+{
+    (void) notifier;
+    (void) data;
+
+    smbios_resolve_devices();
+}
+
 static FWCfgState *bochs_bios_init(void)
 {
     FWCfgState *fw_cfg;
@@ -654,6 +662,10 @@ static FWCfgState *bochs_bios_init(void)
     if (smbios_table)
         fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
                          smbios_table, smbios_len);
+    Notifier *smbios_machine_done = g_malloc0(sizeof(*smbios_machine_done));
+    smbios_machine_done->notify = bochs_bios_machine_done;
+    qemu_add_machine_init_done_notifier(smbios_machine_done);
+
     fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
                      &e820_reserve, sizeof(e820_reserve));
     fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index 355beb9..1be4e3a 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -109,6 +109,12 @@ static const struct {
     }
 };
 
+static struct unresolved_devs {
+    char *id;
+    ptrdiff_t bus_off, dev_func_off;
+} *unresolved_devs;
+static unsigned int unresolved_devs_count;
+
 static QemuOptsList qemu_smbios_opts = {
     .name = "smbios",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
@@ -259,7 +265,7 @@ static void smbios_check_collision(int type, int entry)
     }
 }
 
-static void smbios_add_field(int type, int offset, const void *data, size_t 
len)
+static void *smbios_alloc_field(int type, int offset, size_t len)
 {
     struct smbios_field *field;
 
@@ -275,11 +281,24 @@ static void smbios_add_field(int type, int offset, const 
void *data, size_t len)
 
     field->type = type;
     field->offset = cpu_to_le16(offset);
-    memcpy(field->data, data, len);
 
     smbios_entries_len += sizeof(*field) + len;
     (*(uint16_t *)smbios_entries) =
             cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+
+    return field->data;
+}
+
+static void smbios_add_field(int type, int offset, const void *data, size_t 
len)
+{
+    void *field = smbios_alloc_field(type, offset, len);
+    memcpy(field, data, len);
+}
+
+static ptrdiff_t smbios_alloc_field_off(int type, int offset, size_t len)
+{
+    void *field = smbios_alloc_field(type, offset, len);
+    return field - (void *)smbios_entries;
 }
 
 static void smbios_maybe_add_str(int type, int offset, const char *data)
@@ -374,9 +393,7 @@ static void smbios_entry_add_type_41(QemuOpts *opts)
     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;
+    const char *address, *id;
 
     /* Reference Designation */
     designation = qemu_opt_get(opts, "designation");
@@ -443,30 +460,100 @@ static void smbios_entry_add_type_41(QemuOpts *opts)
 
     /* Segment Group Number, Bus Number and Device/Function Number */
     address = qemu_opt_get(opts, "address");
-    if (!address) {
-        error_report("You should specify address");
+    id = qemu_opts_id(opts);
+    if (!address && !id) {
+        error_report("You should specify address or id");
         exit(1);
     }
-    if (pci_parse_devaddr(address, &seg, &bus, &dev, &func) < 0) {
-        error_report("Invalid address");
+    if (address && id) {
+        error_report("You should specify address OR id, not both");
         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));
+    if (address) {
+        int seg, bus;
+        unsigned int dev, func;
+        if (pci_parse_devaddr(address, &seg, &bus, &dev, &func) < 0) {
+            error_report("Invalid device 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));
+    }
+
+    if (id) {
+        if (unresolved_devs) {
+            unresolved_devs_count++;
+            unresolved_devs = g_realloc(unresolved_devs,
+                    sizeof(*unresolved_devs) * unresolved_devs_count);
+        } else {
+            unresolved_devs_count = 1;
+            unresolved_devs = g_malloc0(sizeof(*unresolved_devs));
+        }
+        struct unresolved_devs *unresolved =
+                &unresolved_devs[unresolved_devs_count - 1];
+
+        unresolved->id = g_strdup(id);
+        smbios_add_field(41,
+                offsetof(struct smbios_type_41, segment_group_number),
+                &(uint16_t){ 0 }, /* QEMU supports only zero PCI domain. */
+                sizeof(uint16_t));
+        unresolved->bus_off = smbios_alloc_field_off(41,
+                offsetof(struct smbios_type_41, bus_number),
+                sizeof(uint8_t));
+        unresolved->dev_func_off = smbios_alloc_field_off(41,
+                offsetof(struct smbios_type_41, device_function_number),
+                sizeof(uint8_t));
+    }
 
     smbios_add_fields_set_end_marker(41);
 }
 
+void smbios_resolve_devices(void)
+{
+    if (!unresolved_devs) {
+        return;
+    }
+
+    unsigned int i;
+    struct unresolved_devs *unresolved = unresolved_devs;
+    for (i = 0; i < unresolved_devs_count; i++) {
+        DeviceState *qdev = qdev_find_recursive(sysbus_get_default(),
+                                                unresolved->id);
+        if (!qdev) {
+            error_report("smbios: Unable to find device \"%s\"",
+                         unresolved->id);
+            exit(1);
+        }
+
+        PCIDevice *dev = (PCIDevice *)object_dynamic_cast(OBJECT(qdev),
+                                                          TYPE_PCI_DEVICE);
+        if (!dev) {
+            error_report("smbios: \"%s\" is not PCI device", unresolved->id);
+            exit(1);
+        }
+
+        smbios_entries[unresolved->bus_off] = pci_bus_num(dev->bus);
+        smbios_entries[unresolved->dev_func_off] = dev->devfn;
+
+        g_free(unresolved->id);
+        unresolved++;
+    }
+
+    g_free(unresolved_devs);
+    unresolved_devs = NULL;
+}
+
 void smbios_entry_add(QemuOpts *opts)
 {
     Error *local_err = NULL;
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
index a57ffc9..91a28a7 100644
--- a/include/hw/i386/smbios.h
+++ b/include/hw/i386/smbios.h
@@ -17,6 +17,7 @@
 
 void smbios_entry_add(QemuOpts *opts);
 uint8_t *smbios_get_table(size_t *length);
+void smbios_resolve_devices(void);
 
 /*
  * SMBIOS spec defined tables
diff --git a/qemu-options.hx b/qemu-options.hx
index a3b4b78..98298cf 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1323,6 +1323,8 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
     "                specify SMBIOS type 1 fields\n"
     "-smbios type=41,address=str,instance=n[,designation=str]\n"
     "              [,status=on|off][,device-type=str|n]\n"
+    "-smbios type=41,id=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
@@ -1336,9 +1338,10 @@ Specify SMBIOS type 0 fields
 Specify SMBIOS type 1 fields
 
 @item -smbios 
type=41,address@hidden,address@hidden,address@hidden,status=on|off][,address@hidden|n}]
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 in form "[[<domain>:]<bus>:]<slot>.<func>" or @option{id}, and
 @option{instance} 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
@@ -1365,6 +1368,9 @@ 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 \
+-netdev user,id=hostnet1 \
+-device e1000,netdev=hostnet1,id=net1 \
+-smbios type=41,id=net1,instance=2,designation="NIC 2",device-type=ethernet \
 < ... other qemu options ... >
 @end example
 ETEXI
-- 
1.8.4.1




reply via email to

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