[SeaBIOS] [SeaBIOS v2 PATCH] SMBIOS: Check for full tables & entry point in fw_cfg
Gabriel L. Somlo
gsomlo at gmail.com
Fri Apr 11 18:42:52 CEST 2014
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 <somlo at cmu.edu>
---
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
More information about the SeaBIOS
mailing list