9ae3a8
From 3a4932455a7f7926b673089170f55de437eec5fa Mon Sep 17 00:00:00 2001
9ae3a8
From: Markus Armbruster <armbru@redhat.com>
9ae3a8
Date: Sat, 2 Nov 2013 10:01:22 +0100
9ae3a8
Subject: [PATCH 22/29] smbios: Improve diagnostics for conflicting entries
9ae3a8
9ae3a8
RH-Author: Markus Armbruster <armbru@redhat.com>
9ae3a8
Message-id: <1383386488-29789-6-git-send-email-armbru@redhat.com>
9ae3a8
Patchwork-id: 55243
9ae3a8
O-Subject: [PATCH 7.0 qemu-kvm 05/11] smbios: Improve diagnostics for conflicting entries
9ae3a8
Bugzilla: 994490
9ae3a8
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
From: Markus Armbruster <armbru@redhat.com>
9ae3a8
9ae3a8
We allow either tables or fields for the same type.  Makes sense,
9ae3a8
because SeaBIOS uses fields only when no tables are present.
9ae3a8
9ae3a8
We do this by searching the SMBIOS blob for a previously added table
9ae3a8
or field.  Error messages look like this:
9ae3a8
9ae3a8
    qemu-system-x86_64: -smbios type=1,serial=42: SMBIOS type 1 table already defined, cannot add field
9ae3a8
9ae3a8
User needs to know that "table" is defined by -smbios file=..., and
9ae3a8
"field" by -smbios type=...
9ae3a8
9ae3a8
Instead of searching the blob, record additions of interest, and check
9ae3a8
that.  Simpler, and makes better error messages possible:
9ae3a8
9ae3a8
    qemu-system-x86_64: -smbios file=smbios_type_1.bin: Can't mix file= and type= for same type
9ae3a8
    qemu-system-x86_64: -smbios type=1,serial=42,serial=99: This is the conflicting setting
9ae3a8
9ae3a8
Signed-off-by: Markus Armbruster <armbru@redhat.com>
9ae3a8
Reviewed-by: Eric Blake <eblake@redhat.com>
9ae3a8
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
(cherry picked from commit ec2df8c10a4585ba4641ae482cf2f5f13daa810e)
9ae3a8
---
9ae3a8
 hw/i386/smbios.c | 43 +++++++++++++++++--------------------------
9ae3a8
 1 file changed, 17 insertions(+), 26 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/i386/smbios.c |   43 +++++++++++++++++--------------------------
9ae3a8
 1 files changed, 17 insertions(+), 26 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
9ae3a8
index abfd6f7..4263551 100644
9ae3a8
--- a/hw/i386/smbios.c
9ae3a8
+++ b/hw/i386/smbios.c
9ae3a8
@@ -48,6 +48,12 @@ static uint8_t *smbios_entries;
9ae3a8
 static size_t smbios_entries_len;
9ae3a8
 static int smbios_type4_count = 0;
9ae3a8
 
9ae3a8
+static struct {
9ae3a8
+    bool seen;
9ae3a8
+    int headertype;
9ae3a8
+    Location loc;
9ae3a8
+} first_opt[2];
9ae3a8
+
9ae3a8
 static QemuOptsList qemu_smbios_opts = {
9ae3a8
     .name = "smbios",
9ae3a8
     .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
9ae3a8
@@ -159,35 +165,20 @@ uint8_t *smbios_get_table(size_t *length)
9ae3a8
  */
9ae3a8
 static void smbios_check_collision(int type, int entry)
9ae3a8
 {
9ae3a8
-    uint16_t *num_entries = (uint16_t *)smbios_entries;
9ae3a8
-    struct smbios_header *header;
9ae3a8
-    char *p;
9ae3a8
-    int i;
9ae3a8
-
9ae3a8
-    if (!num_entries)
9ae3a8
-        return;
9ae3a8
-
9ae3a8
-    p = (char *)(num_entries + 1);
9ae3a8
-
9ae3a8
-    for (i = 0; i < *num_entries; i++) {
9ae3a8
-        header = (struct smbios_header *)p;
9ae3a8
-        if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
9ae3a8
-            struct smbios_field *field = (void *)header;
9ae3a8
-            if (type == field->type) {
9ae3a8
-                error_report("SMBIOS type %d field already defined, "
9ae3a8
-                             "cannot add table", type);
9ae3a8
-                exit(1);
9ae3a8
-            }
9ae3a8
-        } else if (entry == SMBIOS_FIELD_ENTRY &&
9ae3a8
-                   header->type == SMBIOS_TABLE_ENTRY) {
9ae3a8
-            struct smbios_structure_header *table = (void *)(header + 1);
9ae3a8
-            if (type == table->type) {
9ae3a8
-                error_report("SMBIOS type %d table already defined, "
9ae3a8
-                             "cannot add field", type);
9ae3a8
+    if (type < ARRAY_SIZE(first_opt)) {
9ae3a8
+        if (first_opt[type].seen) {
9ae3a8
+            if (first_opt[type].headertype != entry) {
9ae3a8
+                error_report("Can't mix file= and type= for same type");
9ae3a8
+                loc_push_restore(&first_opt[type].loc);
9ae3a8
+                error_report("This is the conflicting setting");
9ae3a8
+                loc_pop(&first_opt[type].loc);
9ae3a8
                 exit(1);
9ae3a8
             }
9ae3a8
+        } else {
9ae3a8
+            first_opt[type].seen = true;
9ae3a8
+            first_opt[type].headertype = entry;
9ae3a8
+            loc_save(&first_opt[type].loc);
9ae3a8
         }
9ae3a8
-        p += le16_to_cpu(header->length);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8