qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [SeaBIOS v2 PATCH] SMBIOS: Check for full tables & entry po


From: Gabriel L. Somlo
Subject: [Qemu-devel] [SeaBIOS v2 PATCH] SMBIOS: Check for full tables & entry point in fw_cfg
Date: Fri, 11 Apr 2014 12:42:52 -0400
User-agent: Mutt/1.5.21 (2010-09-15)

Check fw_cfg for the presence of a complete set of smbios tables
(etc/smbios/smbios-tables), and an entry point structure
(etc/smbios/smbios-anchor). If found, we no longer build smbios
tables locally; instead, we replace only the type 0 table with a
default of our own, and (re)calculate only the minimum set of
necessary fields from the provided entry point.

Signed-off-by: Gabriel L. Somlo <address@hidden>
---

Reworked to fit on top of 028f3487cfaa136815dd8d1896310c763402e969.
Thanks,
  Gabriel

 src/fw/smbios.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/src/fw/smbios.c b/src/fw/smbios.c
index 0ac9ff5..b38d199 100644
--- a/src/fw/smbios.c
+++ b/src/fw/smbios.c
@@ -160,6 +160,60 @@ get_external(int type, char **p, unsigned *nr_structs,
         }                                                               \
     } while (0)
 
+#define set_str_field_or_skip(type, field, value)                       \
+    do {                                                                \
+        int size = (value != NULL) ? strlen(value) + 1 : 0;             \
+        if (size > 1) {                                                 \
+            memcpy(end, value, size);                                   \
+            end += size;                                                \
+            p->field = ++str_index;                                     \
+        } else {                                                        \
+            p->field = 0;                                               \
+        }                                                               \
+    } while (0)
+
+static void *
+smbios_new_type_0(void *start,
+                  const char *vendor, const char *version, const char 
*rel_date)
+{
+    struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+    char *end = (char *)start + sizeof(struct smbios_type_0);
+    int str_index = 0;
+
+    p->header.type = 0;
+    p->header.length = sizeof(struct smbios_type_0);
+    p->header.handle = 0;
+
+    set_str_field_or_skip(0, vendor_str, vendor);
+    set_str_field_or_skip(0, bios_version_str, version);
+    p->bios_starting_address_segment = 0xe800;
+    set_str_field_or_skip(0, bios_release_date_str, rel_date);
+
+    p->bios_rom_size = 0; /* FIXME */
+
+    /* BIOS characteristics not supported */
+    memset(p->bios_characteristics, 0, 8);
+    p->bios_characteristics[0] = 0x08;
+
+    /* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */
+    p->bios_characteristics_extension_bytes[0] = 0;
+    p->bios_characteristics_extension_bytes[1] = 4;
+
+    p->system_bios_major_release = 0;
+    p->system_bios_minor_release = 0;
+    p->embedded_controller_major_release = 0xFF;
+    p->embedded_controller_minor_release = 0xFF;
+
+    *end = 0;
+    end++;
+    if (!str_index) {
+        *end = 0;
+        end++;
+    }
+
+    return end;
+}
+
 /* Type 0 -- BIOS Information */
 #define RELEASE_DATE_STR "01/01/2011"
 static void *
@@ -501,6 +555,82 @@ smbios_init_type_127(void *start)
     return start + 2;
 }
 
+static int
+smbios_try_fw_cfg_setup(void)
+{
+    struct romfile_s *f_anchor = romfile_find("etc/smbios/smbios-anchor");
+    struct romfile_s *f_tables = romfile_find("etc/smbios/smbios-tables");
+    struct smbios_entry_point ep;
+    u8 *tables, *t;
+    u16 t_len;
+
+    if (!f_anchor || !f_tables || f_anchor->size != sizeof(ep))
+        return 0;
+
+    f_anchor->copy(f_anchor, &ep, f_anchor->size);
+
+    if (f_tables->size != ep.structure_table_length)
+        return 0;
+
+    tables = malloc_tmphigh(f_tables->size);
+    if (!tables) {
+        warn_noalloc();
+        return 0;
+    }
+    f_tables->copy(f_tables, tables, f_tables->size);
+
+    /* rip out any type 0 tables we may have received */
+    t = tables;
+    t_len = ep.structure_table_length;
+    while (t < tables + t_len) {
+        struct smbios_structure_header *h = (struct smbios_structure_header 
*)t;
+        u8 *next;
+
+        /* find start of next structure (past the double-'\0' terminator) */
+        for (next = t + h->length; *next || *(next+1); next++);
+        next += 2;
+
+        if (h->type == 0) {
+            /* move remaining tables down over t */
+            memmove(t, next, t_len - (next - tables));
+            /* shorten total blob length */
+            t_len -= (next - t);
+        } else {
+            t = next;
+        }
+    }
+
+    /* final blob length adds our own type 0 with 3 strings and 4 '\0's */
+    ep.structure_table_length = t_len + sizeof(struct smbios_type_0) +
+                                strlen("SeaBIOS") + strlen(VERSION) +
+                                strlen(RELEASE_DATE_STR) + 4;
+
+    /* allocate final blob */
+    if (ep.structure_table_length > BUILD_MAX_SMBIOS_FSEG)
+        t = malloc_high(ep.structure_table_length);
+    else
+        t = malloc_fseg(ep.structure_table_length);
+    if (!t) {
+        warn_noalloc();
+        free(tables);
+        return 0;
+    }
+
+    /* finalize entry point */
+    ep.structure_table_address = (u32)t;
+    ep.checksum = -checksum(&ep, 0x10);
+    ep.intermediate_checksum = -checksum((void *)&ep + 0x10, ep.length - 0x10);
+
+    /* populate final blob */
+    t = smbios_new_type_0(t, "SeaBIOS", VERSION, RELEASE_DATE_STR);
+    memcpy(t, tables, t_len);
+    free(tables);
+
+    /* success */
+    copy_smbios(&ep);
+    return 1;
+}
+
 #define TEMPSMBIOSSIZE (32 * 1024)
 
 void
@@ -511,6 +641,9 @@ smbios_setup(void)
 
     dprintf(3, "init SMBIOS tables\n");
 
+    if (smbios_try_fw_cfg_setup())
+        return; /* got full tables via fw_cfg, we're done */
+
     char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
     if (! start) {
         warn_noalloc();
-- 
1.9.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]