|
|
218e99 |
From f602774bca68ddc853f88cf90c62e1af94390731 Mon Sep 17 00:00:00 2001
|
|
|
218e99 |
From: Markus Armbruster <armbru@redhat.com>
|
|
|
218e99 |
Date: Wed, 6 Nov 2013 09:09:09 +0100
|
|
|
218e99 |
Subject: [PATCH 23/29] smbios: Make multiple -smbios type= accumulate sanely
|
|
|
218e99 |
|
|
|
218e99 |
RH-Author: Markus Armbruster <armbru@redhat.com>
|
|
|
218e99 |
Message-id: <1383386488-29789-7-git-send-email-armbru@redhat.com>
|
|
|
218e99 |
Patchwork-id: 55244
|
|
|
218e99 |
O-Subject: [PATCH 7.0 qemu-kvm 06/11] smbios: Make multiple -smbios type= accumulate sanely
|
|
|
218e99 |
Bugzilla: 994490
|
|
|
218e99 |
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
218e99 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
218e99 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
218e99 |
|
|
|
218e99 |
From: Markus Armbruster <armbru@redhat.com>
|
|
|
218e99 |
|
|
|
218e99 |
Currently, -smbios type=T,NAME=VAL,... adds one field (T,NAME) with
|
|
|
218e99 |
value VAL to fw_cfg for each unique NAME. If NAME occurs multiple
|
|
|
218e99 |
times, the last one's VAL is used (before the QemuOpts conversion, the
|
|
|
218e99 |
first one was used).
|
|
|
218e99 |
|
|
|
218e99 |
Multiple -smbios can add multiple fields with the same (T, NAME).
|
|
|
218e99 |
SeaBIOS reads all of them from fw_cfg, but uses only the first field
|
|
|
218e99 |
(T, NAME). The others are ignored.
|
|
|
218e99 |
|
|
|
218e99 |
"First one wins, subsequent ones get ignored silently" isn't nice. We
|
|
|
218e99 |
commonly let the last option win. Useful, because it lets you
|
|
|
218e99 |
-readconfig first, then selectively override with command line
|
|
|
218e99 |
options.
|
|
|
218e99 |
|
|
|
218e99 |
Clean up -smbios to work the common way. Accumulate the settings,
|
|
|
218e99 |
with later ones overwriting earlier ones. Put the result into fw_cfg
|
|
|
218e99 |
(no more useless duplicates).
|
|
|
218e99 |
|
|
|
218e99 |
Bonus cleanup: qemu_uuid_parse() no longer sets SMBIOS system uuid by
|
|
|
218e99 |
side effect.
|
|
|
218e99 |
|
|
|
218e99 |
Signed-off-by: Markus Armbruster <armbru@redhat.com>
|
|
|
218e99 |
Reviewed-by: Eric Blake <eblake@redhat.com>
|
|
|
218e99 |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
218e99 |
(cherry picked from commit fc3b32958a80bca13309e2695de07b43dd788421)
|
|
|
218e99 |
|
|
|
218e99 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
218e99 |
---
|
|
|
218e99 |
arch_init.c | 3 -
|
|
|
218e99 |
hw/i386/smbios.c | 152 +++++++++++++++++++++++++++------------------
|
|
|
218e99 |
include/hw/i386/smbios.h | 1 -
|
|
|
218e99 |
include/sysemu/sysemu.h | 1 +
|
|
|
218e99 |
vl.c | 2 +
|
|
|
218e99 |
5 files changed, 94 insertions(+), 65 deletions(-)
|
|
|
218e99 |
|
|
|
218e99 |
diff --git a/arch_init.c b/arch_init.c
|
|
|
218e99 |
index d8c4e2e..5301cfd 100644
|
|
|
218e99 |
--- a/arch_init.c
|
|
|
218e99 |
+++ b/arch_init.c
|
|
|
218e99 |
@@ -1056,9 +1056,6 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid)
|
|
|
218e99 |
if (ret != 16) {
|
|
|
218e99 |
return -1;
|
|
|
218e99 |
}
|
|
|
218e99 |
-#ifdef TARGET_I386
|
|
|
218e99 |
- smbios_add_field(1, offsetof(struct smbios_type_1, uuid), uuid, 16);
|
|
|
218e99 |
-#endif
|
|
|
218e99 |
return 0;
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
|
|
|
218e99 |
index 4263551..d2dba6c 100644
|
|
|
218e99 |
--- a/hw/i386/smbios.c
|
|
|
218e99 |
+++ b/hw/i386/smbios.c
|
|
|
218e99 |
@@ -47,6 +47,7 @@ struct smbios_table {
|
|
|
218e99 |
static uint8_t *smbios_entries;
|
|
|
218e99 |
static size_t smbios_entries_len;
|
|
|
218e99 |
static int smbios_type4_count = 0;
|
|
|
218e99 |
+static bool smbios_immutable;
|
|
|
218e99 |
|
|
|
218e99 |
static struct {
|
|
|
218e99 |
bool seen;
|
|
|
218e99 |
@@ -54,6 +55,17 @@ static struct {
|
|
|
218e99 |
Location loc;
|
|
|
218e99 |
} first_opt[2];
|
|
|
218e99 |
|
|
|
218e99 |
+static struct {
|
|
|
218e99 |
+ const char *vendor, *version, *date;
|
|
|
218e99 |
+ bool have_major_minor;
|
|
|
218e99 |
+ uint8_t major, minor;
|
|
|
218e99 |
+} type0;
|
|
|
218e99 |
+
|
|
|
218e99 |
+static struct {
|
|
|
218e99 |
+ const char *manufacturer, *product, *version, *serial, *sku, *family;
|
|
|
218e99 |
+ /* uuid is in qemu_uuid[] */
|
|
|
218e99 |
+} type1;
|
|
|
218e99 |
+
|
|
|
218e99 |
static QemuOptsList qemu_smbios_opts = {
|
|
|
218e99 |
.name = "smbios",
|
|
|
218e99 |
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
|
|
|
218e99 |
@@ -152,13 +164,6 @@ static void smbios_validate_table(void)
|
|
|
218e99 |
}
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
-uint8_t *smbios_get_table(size_t *length)
|
|
|
218e99 |
-{
|
|
|
218e99 |
- smbios_validate_table();
|
|
|
218e99 |
- *length = smbios_entries_len;
|
|
|
218e99 |
- return smbios_entries;
|
|
|
218e99 |
-}
|
|
|
218e99 |
-
|
|
|
218e99 |
/*
|
|
|
218e99 |
* To avoid unresolvable overlaps in data, don't allow both
|
|
|
218e99 |
* tables and fields for the same smbios type.
|
|
|
218e99 |
@@ -182,12 +187,10 @@ static void smbios_check_collision(int type, int entry)
|
|
|
218e99 |
}
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
-void smbios_add_field(int type, int offset, const void *data, size_t len)
|
|
|
218e99 |
+static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
|
|
218e99 |
{
|
|
|
218e99 |
struct smbios_field *field;
|
|
|
218e99 |
|
|
|
218e99 |
- smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
|
|
|
218e99 |
-
|
|
|
218e99 |
if (!smbios_entries) {
|
|
|
218e99 |
smbios_entries_len = sizeof(uint16_t);
|
|
|
218e99 |
smbios_entries = g_malloc0(smbios_entries_len);
|
|
|
218e99 |
@@ -207,82 +210,81 @@ void smbios_add_field(int type, int offset, const void *data, size_t len)
|
|
|
218e99 |
cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
-static void smbios_build_type_0_fields(QemuOpts *opts)
|
|
|
218e99 |
+static void smbios_build_type_0_fields(void)
|
|
|
218e99 |
{
|
|
|
218e99 |
- const char *val;
|
|
|
218e99 |
- unsigned char major, minor;
|
|
|
218e99 |
-
|
|
|
218e99 |
- val = qemu_opt_get(opts, "vendor");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type0.vendor) {
|
|
|
218e99 |
smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type0.vendor, strlen(type0.vendor) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "version");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type0.version) {
|
|
|
218e99 |
smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type0.version, strlen(type0.version) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "date");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type0.date) {
|
|
|
218e99 |
smbios_add_field(0, offsetof(struct smbios_type_0,
|
|
|
218e99 |
bios_release_date_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type0.date, strlen(type0.date) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "release");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
- if (sscanf(val, "%hhu.%hhu", &major, &minor) != 2) {
|
|
|
218e99 |
- error_report("Invalid release");
|
|
|
218e99 |
- exit(1);
|
|
|
218e99 |
- }
|
|
|
218e99 |
+ if (type0.have_major_minor) {
|
|
|
218e99 |
smbios_add_field(0, offsetof(struct smbios_type_0,
|
|
|
218e99 |
system_bios_major_release),
|
|
|
218e99 |
- &major, 1);
|
|
|
218e99 |
+ &type0.major, 1);
|
|
|
218e99 |
smbios_add_field(0, offsetof(struct smbios_type_0,
|
|
|
218e99 |
system_bios_minor_release),
|
|
|
218e99 |
- &minor, 1);
|
|
|
218e99 |
+ &type0.minor, 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
-static void smbios_build_type_1_fields(QemuOpts *opts)
|
|
|
218e99 |
+static void smbios_build_type_1_fields(void)
|
|
|
218e99 |
{
|
|
|
218e99 |
- const char *val;
|
|
|
218e99 |
-
|
|
|
218e99 |
- val = qemu_opt_get(opts, "manufacturer");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.manufacturer) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type1.manufacturer, strlen(type1.manufacturer) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "product");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.product) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type1.product, strlen(type1.product) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "version");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.version) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type1.version, strlen(type1.version) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "serial");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.serial) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
- }
|
|
|
218e99 |
- val = qemu_opt_get(opts, "uuid");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
- if (qemu_uuid_parse(val, qemu_uuid) != 0) {
|
|
|
218e99 |
- error_report("Invalid UUID");
|
|
|
218e99 |
- exit(1);
|
|
|
218e99 |
- }
|
|
|
218e99 |
+ type1.serial, strlen(type1.serial) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "sku");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.sku) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type1.sku, strlen(type1.sku) + 1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- val = qemu_opt_get(opts, "family");
|
|
|
218e99 |
- if (val) {
|
|
|
218e99 |
+ if (type1.family) {
|
|
|
218e99 |
smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
|
|
|
218e99 |
- val, strlen(val) + 1);
|
|
|
218e99 |
+ type1.family, strlen(type1.family) + 1);
|
|
|
218e99 |
+ }
|
|
|
218e99 |
+ if (qemu_uuid_set) {
|
|
|
218e99 |
+ smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
|
|
|
218e99 |
+ qemu_uuid, 16);
|
|
|
218e99 |
+ }
|
|
|
218e99 |
+}
|
|
|
218e99 |
+
|
|
|
218e99 |
+uint8_t *smbios_get_table(size_t *length)
|
|
|
218e99 |
+{
|
|
|
218e99 |
+ if (!smbios_immutable) {
|
|
|
218e99 |
+ smbios_build_type_0_fields();
|
|
|
218e99 |
+ smbios_build_type_1_fields();
|
|
|
218e99 |
+ smbios_validate_table();
|
|
|
218e99 |
+ smbios_immutable = true;
|
|
|
218e99 |
+ }
|
|
|
218e99 |
+ *length = smbios_entries_len;
|
|
|
218e99 |
+ return smbios_entries;
|
|
|
218e99 |
+}
|
|
|
218e99 |
+
|
|
|
218e99 |
+static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
|
|
218e99 |
+{
|
|
|
218e99 |
+ const char *val = qemu_opt_get(opts, name);
|
|
|
218e99 |
+
|
|
|
218e99 |
+ if (val) {
|
|
|
218e99 |
+ *dest = val;
|
|
|
218e99 |
}
|
|
|
218e99 |
}
|
|
|
218e99 |
|
|
|
218e99 |
@@ -291,6 +293,7 @@ void smbios_entry_add(QemuOpts *opts)
|
|
|
218e99 |
Error *local_err = NULL;
|
|
|
218e99 |
const char *val;
|
|
|
218e99 |
|
|
|
218e99 |
+ assert(!smbios_immutable);
|
|
|
218e99 |
val = qemu_opt_get(opts, "file");
|
|
|
218e99 |
if (val) {
|
|
|
218e99 |
struct smbios_structure_header *header;
|
|
|
218e99 |
@@ -341,6 +344,8 @@ void smbios_entry_add(QemuOpts *opts)
|
|
|
218e99 |
if (val) {
|
|
|
218e99 |
unsigned long type = strtoul(val, NULL, 0);
|
|
|
218e99 |
|
|
|
218e99 |
+ smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
|
|
|
218e99 |
+
|
|
|
218e99 |
switch (type) {
|
|
|
218e99 |
case 0:
|
|
|
218e99 |
qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err);
|
|
|
218e99 |
@@ -348,7 +353,18 @@ void smbios_entry_add(QemuOpts *opts)
|
|
|
218e99 |
error_report("%s", error_get_pretty(local_err));
|
|
|
218e99 |
exit(1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- smbios_build_type_0_fields(opts);
|
|
|
218e99 |
+ save_opt(&type0.vendor, opts, "vendor");
|
|
|
218e99 |
+ save_opt(&type0.version, opts, "version");
|
|
|
218e99 |
+ save_opt(&type0.date, opts, "date");
|
|
|
218e99 |
+
|
|
|
218e99 |
+ val = qemu_opt_get(opts, "release");
|
|
|
218e99 |
+ if (val) {
|
|
|
218e99 |
+ if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
|
|
|
218e99 |
+ error_report("Invalid release");
|
|
|
218e99 |
+ exit(1);
|
|
|
218e99 |
+ }
|
|
|
218e99 |
+ type0.have_major_minor = true;
|
|
|
218e99 |
+ }
|
|
|
218e99 |
return;
|
|
|
218e99 |
case 1:
|
|
|
218e99 |
qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err);
|
|
|
218e99 |
@@ -356,7 +372,21 @@ void smbios_entry_add(QemuOpts *opts)
|
|
|
218e99 |
error_report("%s", error_get_pretty(local_err));
|
|
|
218e99 |
exit(1);
|
|
|
218e99 |
}
|
|
|
218e99 |
- smbios_build_type_1_fields(opts);
|
|
|
218e99 |
+ save_opt(&type1.manufacturer, opts, "manufacturer");
|
|
|
218e99 |
+ save_opt(&type1.product, opts, "product");
|
|
|
218e99 |
+ save_opt(&type1.version, opts, "version");
|
|
|
218e99 |
+ save_opt(&type1.serial, opts, "serial");
|
|
|
218e99 |
+ save_opt(&type1.sku, opts, "sku");
|
|
|
218e99 |
+ save_opt(&type1.family, opts, "family");
|
|
|
218e99 |
+
|
|
|
218e99 |
+ val = qemu_opt_get(opts, "uuid");
|
|
|
218e99 |
+ if (val) {
|
|
|
218e99 |
+ if (qemu_uuid_parse(val, qemu_uuid) != 0) {
|
|
|
218e99 |
+ error_report("Invalid UUID");
|
|
|
218e99 |
+ exit(1);
|
|
|
218e99 |
+ }
|
|
|
218e99 |
+ qemu_uuid_set = true;
|
|
|
218e99 |
+ }
|
|
|
218e99 |
return;
|
|
|
218e99 |
default:
|
|
|
218e99 |
error_report("Don't know how to build fields for SMBIOS type %ld",
|
|
|
218e99 |
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
|
|
|
218e99 |
index d9f43b7..b08ec71 100644
|
|
|
218e99 |
--- a/include/hw/i386/smbios.h
|
|
|
218e99 |
+++ b/include/hw/i386/smbios.h
|
|
|
218e99 |
@@ -16,7 +16,6 @@
|
|
|
218e99 |
#include "qemu/option.h"
|
|
|
218e99 |
|
|
|
218e99 |
void smbios_entry_add(QemuOpts *opts);
|
|
|
218e99 |
-void smbios_add_field(int type, int offset, const void *data, size_t len);
|
|
|
218e99 |
uint8_t *smbios_get_table(size_t *length);
|
|
|
218e99 |
|
|
|
218e99 |
/*
|
|
|
218e99 |
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
|
|
|
218e99 |
index 76c5b64..8fbc818 100644
|
|
|
218e99 |
--- a/include/sysemu/sysemu.h
|
|
|
218e99 |
+++ b/include/sysemu/sysemu.h
|
|
|
218e99 |
@@ -16,6 +16,7 @@ extern const char *bios_name;
|
|
|
218e99 |
|
|
|
218e99 |
extern const char *qemu_name;
|
|
|
218e99 |
extern uint8_t qemu_uuid[];
|
|
|
218e99 |
+extern bool qemu_uuid_set;
|
|
|
218e99 |
int qemu_uuid_parse(const char *str, uint8_t *uuid);
|
|
|
218e99 |
|
|
|
218e99 |
#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
|
|
|
218e99 |
diff --git a/vl.c b/vl.c
|
|
|
218e99 |
index e82eb1c..19cc3b2 100644
|
|
|
218e99 |
--- a/vl.c
|
|
|
218e99 |
+++ b/vl.c
|
|
|
218e99 |
@@ -256,6 +256,7 @@ uint64_t node_mem[MAX_NODES];
|
|
|
218e99 |
unsigned long *node_cpumask[MAX_NODES];
|
|
|
218e99 |
|
|
|
218e99 |
uint8_t qemu_uuid[16];
|
|
|
218e99 |
+bool qemu_uuid_set;
|
|
|
218e99 |
|
|
|
218e99 |
static QEMUBootSetHandler *boot_set_handler;
|
|
|
218e99 |
static void *boot_set_opaque;
|
|
|
218e99 |
@@ -3573,6 +3574,7 @@ int main(int argc, char **argv, char **envp)
|
|
|
218e99 |
" Wrong format.\n");
|
|
|
218e99 |
exit(1);
|
|
|
218e99 |
}
|
|
|
218e99 |
+ qemu_uuid_set = true;
|
|
|
218e99 |
break;
|
|
|
218e99 |
case QEMU_OPTION_option_rom:
|
|
|
218e99 |
if (nb_option_roms >= MAX_OPTION_ROMS) {
|
|
|
218e99 |
--
|
|
|
218e99 |
1.7.1
|
|
|
218e99 |
|