From: Liran Alon <liran.a...@oracle.com>

Windows kernel extracts various BIOS information at boot-time.
The method it uses to extract SystemBiosDate is very hueristic.
It is done by nt!CmpGetBiosDate().

nt!CmpGetBiosDate() works by scanning all BIOS memory from 0xF0000 to
0xFFFF5 (FSEG) in search for a string which is formatted like a date.
It then chooses the string which represents the most recent date, and
writes it to:

    HKLM/HARDWARE/DESCRIPTION/System SystemBiosDate

This date should usually be BiosDate located at FSEG(0xFFF5).

In some cases when the SMBIOS tables are small enough (both in legacy
and non-legacy mode) - These tables are allocated in FSEG instead of
high-mem, specifically Type0->release_date string which might cause
SystemBiosDate to change - depending on its value. This leads to an
inconsistent behaviour that depends on the SMBIOS table sizes.

We fix this inconsistency by changing BiosDate to the same value
provided by SMBIOS, regardless whether SMBIOS tables reside in FSEG or
high-mem.

For reference implementation of nt!CmpGetBiosDate(), see ReactOS:
https://doxygen.reactos.org/d5/dd2/i386_2cmhardwr_8c.html

Reviewed-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com>
Reviewed-by: Arbel Moshe <arbel.mo...@oracle.com>
Signed-off-by: Sam Eiderman <shmuel.eider...@oracle.com>
Signed-off-by: Liran Alon <liran.a...@oracle.com>
---
 src/fw/biostables.c | 36 ++++++++++++++++++++++++++++++++++++
 src/fw/smbios.c     | 20 +++++++++++++++++++-
 src/util.h          |  1 +
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/src/fw/biostables.c b/src/fw/biostables.c
index 546e83c6..90bb3b92 100644
--- a/src/fw/biostables.c
+++ b/src/fw/biostables.c
@@ -268,6 +268,38 @@ smbios_next(struct smbios_entry_point *smbios, void *prev)
     return prev;
 }
 
+// Get string from the smbios table.
+void *
+smbios_get_str(struct smbios_entry_point *smbios, void *offset, u8 n)
+{
+    if (!smbios || !offset || n == 0)
+        return NULL;
+    void *start = (void*)smbios->structure_table_address;
+    void *end = start + smbios->structure_table_length;
+    void *prev = NULL;
+    struct smbios_structure_header *hdr = offset;
+
+    if (offset + sizeof(*hdr) > end)
+        return NULL;
+
+    offset += hdr->length;
+
+    while (n > 0) {
+        prev = offset;
+        while (*(u8*)offset) {
+            if (offset + 3 > end)
+                return NULL; /* not enough space for "\0\0" */
+            offset++;
+        }
+        if (prev == offset)
+            return NULL; /* reached end of table */
+        n--;
+        offset++;
+    }
+
+    return prev;
+}
+
 struct smbios_entry_point *SMBiosAddr;
 
 void
@@ -409,6 +441,7 @@ smbios_romfile_setup(void)
     struct romfile_s *f_tables = romfile_find("etc/smbios/smbios-tables");
     struct smbios_entry_point ep;
     struct smbios_type_0 *t0;
+    char *release_date;
     u16 qtables_len, need_t0 = 1;
     u8 *qtables, *tables;
 
@@ -432,6 +465,9 @@ smbios_romfile_setup(void)
     for (t0 = smbios_next(&ep, NULL); t0; t0 = smbios_next(&ep, t0))
         if (t0->header.type == 0) {
             need_t0 = 0;
+            /* Sync BIOS hardcoded date with the SMBIOS provided one */
+            release_date = smbios_get_str(&ep, t0, t0->bios_release_date_str);
+            smbios_update_bios_date(release_date);
             break;
         }
 
diff --git a/src/fw/smbios.c b/src/fw/smbios.c
index 96104714..7cb02dba 100644
--- a/src/fw/smbios.c
+++ b/src/fw/smbios.c
@@ -160,12 +160,26 @@ get_external(int type, char **p, unsigned *nr_structs,
         }                                                               \
     } while (0)
 
+void
+smbios_update_bios_date(const char *release_date)
+{
+    if (!release_date)
+        return;
+    if (strlen(release_date) == sizeof("mm/dd/yyyy") - 1) {
+        memcpy(BiosDate, release_date, sizeof("mm/dd/") - 1);
+        memcpy(BiosDate + sizeof("mm/dd/") - 1,
+               release_date + sizeof("mm/dd/yy") - 1,
+               sizeof("yy") - 1);
+    }
+}
+
 /* Type 0 -- BIOS Information */
 static void *
 smbios_init_type_0(void *start)
 {
     struct smbios_type_0 *p = (struct smbios_type_0 *)start;
     char *end = (char *)start + sizeof(struct smbios_type_0);
+    char *release_date;
     size_t size;
     int str_index = 0;
 
@@ -178,7 +192,11 @@ smbios_init_type_0(void *start)
 
     p->bios_starting_address_segment = 0xe800;
 
-    load_str_field_with_default(0, bios_release_date_str, BIOS_DATE);
+    /* Sync BIOS hardcoded date with the SMBIOS provided one */
+    release_date = end;
+    load_str_field_with_default(0, bios_release_date_str, BiosDate);
+    if (p->bios_release_date_str)
+        smbios_update_bios_date(release_date);
 
     p->bios_rom_size = 0; /* FIXME */
 
diff --git a/src/util.h b/src/util.h
index 68ba848d..81cddbbd 100644
--- a/src/util.h
+++ b/src/util.h
@@ -84,6 +84,7 @@ void copy_smbios(void *pos);
 void display_uuid(void);
 void copy_table(void *pos);
 void smbios_setup(void);
+void smbios_update_bios_date(const char *release_date);
 
 // fw/coreboot.c
 extern const char *CBvendor, *CBpart;
-- 
2.13.3
_______________________________________________
SeaBIOS mailing list -- seabios@seabios.org
To unsubscribe send an email to seabios-le...@seabios.org

Reply via email to