2019-05-02 00:51:10 +02:00
|
|
|
From: Bruce Rogers <brogers@suse.com>
|
|
|
|
Date: Fri, 5 Apr 2019 21:10:30 -0600
|
|
|
|
Subject: hw/smbios: handle both file formats regardless of machine type
|
|
|
|
|
2019-09-12 17:54:03 +02:00
|
|
|
References: bsc#994082, bsc#1084316, boo#1131894
|
|
|
|
|
2019-05-02 00:51:10 +02:00
|
|
|
It's easy enough to handle either per-spec or legacy smbios structures
|
|
|
|
in the smbios file input without regard to the machine type used, by
|
|
|
|
simply applying the basic smbios formatting rules. then depending on
|
|
|
|
what is detected. terminal numm bytes are added or removed for machine
|
|
|
|
type specific processing.
|
|
|
|
|
|
|
|
Signed-off-by: Bruce Rogers <brogers@suse.com>
|
|
|
|
---
|
|
|
|
hw/smbios/smbios.c | 43 +++++++++++++++++++++++++++++++++++++++----
|
|
|
|
1 file changed, 39 insertions(+), 4 deletions(-)
|
|
|
|
|
|
|
|
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
|
2019-11-27 13:46:32 +01:00
|
|
|
index 11d476c4a2cbdabc546c02b4f076..570ffa3acfa48b3721bdc578ee57 100644
|
2019-05-02 00:51:10 +02:00
|
|
|
--- a/hw/smbios/smbios.c
|
|
|
|
+++ b/hw/smbios/smbios.c
|
2019-11-27 13:46:32 +01:00
|
|
|
@@ -964,6 +964,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
2019-05-02 00:51:10 +02:00
|
|
|
struct smbios_structure_header *header;
|
|
|
|
int size;
|
|
|
|
struct smbios_table *table; /* legacy mode only */
|
|
|
|
+ uint8_t *dbl_nulls, *orig_end;
|
|
|
|
|
|
|
|
qemu_opts_validate(opts, qemu_smbios_file_opts, &err);
|
|
|
|
if (err) {
|
2019-11-27 13:46:32 +01:00
|
|
|
@@ -978,11 +979,21 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
2019-05-02 00:51:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * NOTE: standard double '\0' terminator expected, per smbios spec.
|
|
|
|
- * (except in legacy mode, where the second '\0' is implicit and
|
|
|
|
- * will be inserted by the BIOS).
|
|
|
|
+ * NOTE: standard double '\0' terminator expected, per smbios spec,
|
|
|
|
+ * unless the data is formatted for legacy mode, which is used by
|
|
|
|
+ * pc-i440fx-2.0 and earlier machine types. Legacy mode structures
|
|
|
|
+ * without strings have no '\0' terminators, and those with strings
|
|
|
|
+ * also don't have an additional '\0' terminator at the end of the
|
|
|
|
+ * final string '\0' terminator. The BIOS will add the '\0' terminators
|
|
|
|
+ * to comply with the smbios spec.
|
|
|
|
+ * For greater compatibility, regardless of the machine type used,
|
|
|
|
+ * either format is accepted.
|
|
|
|
*/
|
|
|
|
- smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
|
|
|
+ smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size + 2);
|
|
|
|
+ orig_end = smbios_tables + smbios_tables_len + size;
|
|
|
|
+ /* add extra null bytes to end in case of legacy file data */
|
|
|
|
+ *orig_end = '\0';
|
|
|
|
+ *(orig_end + 1) = '\0';
|
|
|
|
header = (struct smbios_structure_header *)(smbios_tables +
|
|
|
|
smbios_tables_len);
|
|
|
|
|
2019-11-27 13:46:32 +01:00
|
|
|
@@ -997,6 +1008,19 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
2019-05-02 00:51:10 +02:00
|
|
|
header->type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
+ for (dbl_nulls = smbios_tables + smbios_tables_len + header->length;
|
|
|
|
+ dbl_nulls + 2 <= orig_end; dbl_nulls++) {
|
|
|
|
+ if (*dbl_nulls == '\0' && *(dbl_nulls + 1) == '\0') {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (dbl_nulls + 2 < orig_end) {
|
|
|
|
+ error_setg(errp, "SMBIOS file data malformed");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ /* increase size by how many extra nulls were actually needed */
|
|
|
|
+ size += dbl_nulls + 2 - orig_end;
|
|
|
|
+ smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
|
|
|
set_bit(header->type, have_binfile_bitmap);
|
|
|
|
|
|
|
|
if (header->type == 4) {
|
2019-11-27 13:46:32 +01:00
|
|
|
@@ -1017,6 +1041,17 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
2019-05-02 00:51:10 +02:00
|
|
|
* delete the one we don't need from smbios_set_defaults(),
|
|
|
|
* once we know which machine version has been requested.
|
|
|
|
*/
|
|
|
|
+ if (dbl_nulls + 2 == orig_end) {
|
|
|
|
+ /* chop off nulls to get legacy format */
|
|
|
|
+ if (header->length + 2 == size) {
|
|
|
|
+ size -= 2;
|
|
|
|
+ } else {
|
|
|
|
+ size -= 1;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /* undo conversion from legacy format to per-spec format */
|
|
|
|
+ size -= dbl_nulls + 2 - orig_end;
|
|
|
|
+ }
|
|
|
|
if (!smbios_entries) {
|
|
|
|
smbios_entries_len = sizeof(uint16_t);
|
|
|
|
smbios_entries = g_malloc0(smbios_entries_len);
|