[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/2] smbios: Allow device ID instead of PCI address
From: |
Ivan Mironov |
Subject: |
[Qemu-devel] [PATCH 2/2] smbios: Allow device ID instead of PCI address for type 41. |
Date: |
Tue, 19 Nov 2013 20:48:29 +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 c5fccba..49bd6ef 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