[SeaBIOS] [PATCH 3/8] Convert fw_cfg SMBIOS entries into romfile entries.

Kevin O'Connor kevin at koconnor.net
Sun Feb 10 05:47:59 CET 2013


Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/paravirt.c | 174 +++++++++++----------------------------------------------
 src/paravirt.h |   4 --
 src/smbios.c   | 119 +++++++++++++++++++++++++++++----------
 3 files changed, 121 insertions(+), 176 deletions(-)

diff --git a/src/paravirt.c b/src/paravirt.c
index f17930f..e782227 100644
--- a/src/paravirt.c
+++ b/src/paravirt.c
@@ -12,7 +12,7 @@
 #include "byteorder.h" // be32_to_cpu
 #include "ioport.h" // outw
 #include "paravirt.h" // qemu_cfg_preinit
-#include "smbios.h" // struct smbios_structure_header
+#include "smbios.h" // smbios_setup
 #include "memmap.h" // add_e820
 #include "cmos.h" // CMOS_*
 #include "acpi.h" // acpi_setup
@@ -203,18 +203,6 @@ int qemu_cfg_irq0_override(void)
     return v;
 }
 
-u16 qemu_cfg_smbios_entries(void)
-{
-    u16 cnt;
-
-    if (!qemu_cfg_present)
-        return 0;
-
-    qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
-
-    return cnt;
-}
-
 u32 qemu_cfg_e820_entries(void)
 {
     u32 cnt;
@@ -232,134 +220,6 @@ void* qemu_cfg_e820_load_next(void *addr)
     return addr;
 }
 
-struct smbios_header {
-    u16 length;
-    u8 type;
-} PACKED;
-
-struct smbios_field {
-    struct smbios_header header;
-    u8 type;
-    u16 offset;
-    u8 data[];
-} PACKED;
-
-struct smbios_table {
-    struct smbios_header header;
-    u8 data[];
-} PACKED;
-
-#define SMBIOS_FIELD_ENTRY 0
-#define SMBIOS_TABLE_ENTRY 1
-
-size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
-{
-    int i;
-
-    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
-        struct smbios_field field;
-
-        qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
-        field.header.length -= sizeof(struct smbios_header);
-
-        if (field.header.type != SMBIOS_FIELD_ENTRY) {
-            qemu_cfg_skip(field.header.length);
-            continue;
-        }
-
-        qemu_cfg_read((u8 *)&field.type,
-                      sizeof(field) - sizeof(struct smbios_header));
-        field.header.length -= sizeof(field) - sizeof(struct smbios_header);
-
-        if (field.type != type || field.offset != offset) {
-            qemu_cfg_skip(field.header.length);
-            continue;
-        }
-
-        qemu_cfg_read(addr, field.header.length);
-        return (size_t)field.header.length;
-    }
-    return 0;
-}
-
-int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
-                                  unsigned *max_struct_size, char *end)
-{
-    static u64 used_bitmap[4] = { 0 };
-    char *start = *p;
-    int i;
-
-    /* Check if we've already reported these tables */
-    if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
-        return 1;
-
-    /* Don't introduce spurious end markers */
-    if (type == 127)
-        return 0;
-
-    for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
-        struct smbios_table table;
-        struct smbios_structure_header *header = (void *)*p;
-        int string;
-
-        qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
-        table.header.length -= sizeof(struct smbios_header);
-
-        if (table.header.type != SMBIOS_TABLE_ENTRY) {
-            qemu_cfg_skip(table.header.length);
-            continue;
-        }
-
-        if (end - *p < sizeof(struct smbios_structure_header)) {
-            warn_noalloc();
-            break;
-        }
-
-        qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
-        table.header.length -= sizeof(struct smbios_structure_header);
-
-        if (header->type != type) {
-            qemu_cfg_skip(table.header.length);
-            continue;
-        }
-
-        *p += sizeof(struct smbios_structure_header);
-
-        /* Entries end with a double NULL char, if there's a string at
-         * the end (length is greater than formatted length), the string
-         * terminator provides the first NULL. */
-        string = header->length < table.header.length +
-                 sizeof(struct smbios_structure_header);
-
-        /* Read the rest and terminate the entry */
-        if (end - *p < table.header.length) {
-            warn_noalloc();
-            *p -= sizeof(struct smbios_structure_header);
-            continue;
-        }
-        qemu_cfg_read((u8 *)*p, table.header.length);
-        *p += table.header.length;
-        *((u8*)*p) = 0;
-        (*p)++;
-        if (!string) {
-            *((u8*)*p) = 0;
-            (*p)++;
-        }
-
-        (*nr_structs)++;
-        if (*p - (char *)header > *max_struct_size)
-            *max_struct_size = *p - (char *)header;
-    }
-
-    if (start != *p) {
-        /* Mark that we've reported on this type */
-        used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
-        return 1;
-    }
-
-    return 0;
-}
-
 int qemu_cfg_get_numa_nodes(void)
 {
     u64 cnt;
@@ -417,6 +277,16 @@ qemu_romfile_add(char *name, int select, int skip, int size)
     romfile_add(file);
 }
 
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+struct qemu_smbios_header {
+    u16 length;
+    u8 headertype;
+    u8 tabletype;
+    u16 fieldoffset;
+} PACKED;
+
 // Populate romfile entries for legacy fw_cfg ports (that predate the
 // "file" interface).
 static void
@@ -436,6 +306,28 @@ qemu_cfg_legacy(void)
         qemu_cfg_skip(len);
         offset += len;
     }
+
+    // SMBIOS info
+    qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+    offset = sizeof(cnt);
+    for (i = 0; i < cnt; i++) {
+        struct qemu_smbios_header header;
+        qemu_cfg_read(&header, sizeof(header));
+        if (header.headertype == SMBIOS_FIELD_ENTRY) {
+            snprintf(name, sizeof(name), "smbios/field%d-%d"
+                     , header.tabletype, header.fieldoffset);
+            qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+                             , offset + sizeof(header)
+                             , header.length - sizeof(header));
+        } else {
+            snprintf(name, sizeof(name), "smbios/table%d-%d"
+                     , header.tabletype, i);
+            qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
+                             , offset + 3, header.length - 3);
+        }
+        qemu_cfg_skip(header.length - sizeof(header));
+        offset += header.length;
+    }
 }
 
 struct QemuCfgFile {
diff --git a/src/paravirt.h b/src/paravirt.h
index 6836290..6b99ca9 100644
--- a/src/paravirt.h
+++ b/src/paravirt.h
@@ -29,10 +29,6 @@ void qemu_cfg_preinit(void);
 int qemu_cfg_show_boot_menu(void);
 void qemu_cfg_get_uuid(u8 *uuid);
 int qemu_cfg_irq0_override(void);
-u16 qemu_cfg_smbios_entries(void);
-size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr);
-int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
-                                  unsigned *max_struct_size, char *end);
 int qemu_cfg_get_numa_nodes(void);
 void qemu_cfg_get_numa_data(u64 *data, int n);
 u16 qemu_cfg_get_max_cpus(void);
diff --git a/src/smbios.c b/src/smbios.c
index c235564..a9d76f0 100644
--- a/src/smbios.c
+++ b/src/smbios.c
@@ -6,7 +6,7 @@
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "util.h" // dprintf
-#include "paravirt.h" // qemu_cfg_smbios_load_field
+#include "config.h" // CONFIG_*
 #include "smbios.h" // struct smbios_entry_point
 
 struct smbios_entry_point *SMBiosAddr;
@@ -56,11 +56,77 @@ smbios_entry_point_setup(u16 max_structure_size,
             , ep, finaltable, structure_table_length);
 }
 
+static int
+get_field(int type, int offset, void *dest)
+{
+    char name[128];
+    snprintf(name, sizeof(name), "smbios/field%d-%d", type, offset);
+    struct romfile_s *file = romfile_find(name);
+    if (!file)
+        return 0;
+    file->copy(file, dest, file->size);
+    return file->size;
+}
+
+static int
+get_external(int type, char **p, unsigned *nr_structs,
+             unsigned *max_struct_size, char *end)
+{
+    static u64 used_bitmap[4] = { 0 };
+    char *start = *p;
+
+    /* Check if we've already reported these tables */
+    if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+        return 1;
+
+    /* Don't introduce spurious end markers */
+    if (type == 127)
+        return 0;
+
+    char prefix[128];
+    snprintf(prefix, sizeof(prefix), "smbios/table%d-", type);
+    struct romfile_s *file = NULL;
+    for (;;) {
+        file = romfile_findprefix(prefix, file);
+        if (!file)
+            break;
+
+        if (end - *p < file->size) {
+            warn_noalloc();
+            break;
+        }
+
+        struct smbios_structure_header *header = (void*)*p;
+        file->copy(file, header, file->size);
+        *p += file->size;
+
+        /* Entries end with a double NULL char, if there's a string at
+         * the end (length is greater than formatted length), the string
+         * terminator provides the first NULL. */
+        *((u8*)*p) = 0;
+        (*p)++;
+        if (header->length >= file->size) {
+            *((u8*)*p) = 0;
+            (*p)++;
+        }
+
+        (*nr_structs)++;
+        if (*p - (char*)header > *max_struct_size)
+            *max_struct_size = *p - (char*)header;
+    }
+
+    if (start == *p)
+        return 0;
+
+    /* Mark that we've reported on this type */
+    used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+    return 1;
+}
+
 #define load_str_field_with_default(type, field, def)                   \
     do {                                                                \
-        size = qemu_cfg_smbios_load_field(type,                         \
-                                 offsetof(struct smbios_type_##type,    \
-                                          field), end);                 \
+        size = get_field(type, offsetof(struct smbios_type_##type,      \
+                                        field), end);                   \
         if (size > 0) {                                                 \
             end += size;                                                \
         } else {                                                        \
@@ -72,9 +138,8 @@ smbios_entry_point_setup(u16 max_structure_size,
 
 #define load_str_field_or_skip(type, field)                             \
     do {                                                                \
-        size = qemu_cfg_smbios_load_field(type,                         \
-                                 offsetof(struct smbios_type_##type,    \
-                                          field), end);                 \
+        size = get_field(type, offsetof(struct smbios_type_##type,      \
+                                        field), end);                   \
         if (size > 0) {                                                 \
             end += size;                                                \
             p->field = ++str_index;                                     \
@@ -85,9 +150,8 @@ smbios_entry_point_setup(u16 max_structure_size,
 
 #define set_field_with_default(type, field, def)                        \
     do {                                                                \
-        if (!qemu_cfg_smbios_load_field(type,                           \
-                                 offsetof(struct smbios_type_##type,    \
-                                          field), &p->field)) {         \
+        if (!get_field(type, offsetof(struct smbios_type_##type,        \
+                                      field), &p->field)) {             \
             p->field = def;                                             \
         }                                                               \
     } while (0)
@@ -115,17 +179,16 @@ smbios_init_type_0(void *start)
 
     p->bios_rom_size = 0; /* FIXME */
 
-    if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
-                                                bios_characteristics),
-                                    &p->bios_characteristics)) {
+    if (!get_field(0, offsetof(struct smbios_type_0, bios_characteristics),
+                   &p->bios_characteristics)) {
         memset(p->bios_characteristics, 0, 8);
         /* BIOS characteristics not supported */
         p->bios_characteristics[0] = 0x08;
     }
 
-    if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
-                                    bios_characteristics_extension_bytes),
-                                    &p->bios_characteristics_extension_bytes)) {
+    if (!get_field(0, offsetof(struct smbios_type_0,
+                               bios_characteristics_extension_bytes),
+                   &p->bios_characteristics_extension_bytes)) {
         p->bios_characteristics_extension_bytes[0] = 0;
         /* Enable targeted content distribution. Needed for SVVP */
         p->bios_characteristics_extension_bytes[1] = 4;
@@ -160,10 +223,8 @@ smbios_init_type_1(void *start)
     load_str_field_or_skip(1, version_str);
     load_str_field_or_skip(1, serial_number_str);
 
-    if (!qemu_cfg_smbios_load_field(1, offsetof(struct smbios_type_1,
-                                                  uuid), &p->uuid)) {
+    if (!get_field(1, offsetof(struct smbios_type_1, uuid), &p->uuid))
         memset(p->uuid, 0, 16);
-    }
 
     set_field_with_default(1, wake_up_type, 0x06); /* power switch */
 
@@ -234,9 +295,8 @@ smbios_init_type_4(void *start, unsigned int cpu_number)
     p->header.length = sizeof(struct smbios_type_4);
     p->header.handle = 0x400 + cpu_number;
 
-    size = qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
-                                                  socket_designation_str),
-                                                  name);
+    size = get_field(4, offsetof(struct smbios_type_4, socket_designation_str),
+                     name);
     if (size)
         snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
     else
@@ -251,8 +311,8 @@ smbios_init_type_4(void *start, unsigned int cpu_number)
 
     load_str_field_with_default(4, processor_manufacturer_str, CONFIG_APPNAME);
 
-    if (!qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
-                                    processor_id), p->processor_id)) {
+    if (!get_field(4, offsetof(struct smbios_type_4, processor_id)
+                   , p->processor_id)) {
         u32 cpuid_signature, ebx, ecx, cpuid_features;
         cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
         p->processor_id[0] = cpuid_signature;
@@ -332,9 +392,8 @@ smbios_init_type_17(void *start, u32 size_mb, int instance)
     set_field_with_default(17, form_factor, 0x09); /* DIMM */
     p->device_set = 0;
 
-    size = qemu_cfg_smbios_load_field(17, offsetof(struct smbios_type_17,
-                                                   device_locator_str),
-                                                   name);
+    size = get_field(17, offsetof(struct smbios_type_17, device_locator_str),
+                     name);
     if (size)
         snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
     else
@@ -460,8 +519,7 @@ smbios_setup(void)
 
 #define add_struct(type, args...)                                       \
     do {                                                                \
-        if (!qemu_cfg_smbios_load_external(type, &p, &nr_structs,       \
-                                           &max_struct_size, end)) {    \
+        if (!get_external(type, &p, &nr_structs, &max_struct_size, end)) { \
             q = smbios_init_type_##type(args);                          \
             nr_structs++;                                               \
             if ((q - p) > max_struct_size)                              \
@@ -512,8 +570,7 @@ smbios_setup(void)
     add_struct(32, p);
     /* Add any remaining provided entries before the end marker */
     for (i = 0; i < 256; i++)
-        qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,
-                                      end);
+        get_external(i, &p, &nr_structs, &max_struct_size, end);
     add_struct(127, p);
 
 #undef add_struct
-- 
1.7.11.7




More information about the SeaBIOS mailing list