v2:
Offer a better commit for:
"bios_version: Remove misinterpreted version string"
Which doesn't change the debug string but rather creates the original one dynamically. Thanks, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net.
v1:
Windows kernel extracts various BIOS information at boot-time. The method it uses to extract SystemBiosDate & SystemBiosVersion which are then stored in: * "HKLM\HARDWARE\DESCRIPTION\System" "SystemBiosDate" * "HKLM\HARDWARE\DESCRIPTION\System" "SystemBiosVersion" is very hueristic and depends on data contained in the BIOS's data section. The implementation resides in: * nt!CmpGetBiosVersion() * nt!CmpGetBiosDate() respectively. For reference implementation, see ReactOS: https://doxygen.reactos.org/d5/dd2/i386_2cmhardwr_8c.html
This patch series aims to make SeaBIOS's data section interact better with the Windows OS and report correct date & version values.
Liran Alon (4): bios_date: Make all dates in BIOS consistent bios_date: Make bios date appear once in the ROM bios_date: Change BiosDate to SMBIOS bios date bios_version: Remove misinterpreted version string
Sam Eiderman (2): bios_date: Add bios date checks in checkrom.py bios_version: Add bios version checks in checkrom.py
scripts/checkrom.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/config.h | 11 +++++++++++ src/fw/biostables.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- src/fw/pciinit.c | 3 ++- src/fw/smbios.c | 21 +++++++++++++++++++-- src/misc.c | 2 +- src/util.h | 5 +++++ 7 files changed, 130 insertions(+), 8 deletions(-)
From: Liran Alon liran.alon@oracle.com
There are 2 places where SeaBIOS reports its release date:
1. SMBIOS Type 0 entry 2. Hard-coded address 0xFFFF5
Previous to this commit, each of these places defined it's own unique date which doesn't make sense.
Therefore, define the BIOS date in a single place and make sure all relevant places in code use it.
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@oracle.com --- src/config.h | 11 +++++++++++ src/fw/biostables.c | 1 - src/fw/smbios.c | 3 +-- src/misc.c | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/config.h b/src/config.h index 93c8dbc2..6795440c 100644 --- a/src/config.h +++ b/src/config.h @@ -29,6 +29,17 @@ #define BUILD_SUBMODEL_ID 0x00 #define BUILD_BIOS_REVISION 0x01
+#define BIOS_DATE_MONTH "04" +#define BIOS_DATE_DAY "01" +#define BIOS_DATE_YEAR "14" +#define BIOS_DATE_YEAR_PREFIX "20" +#define BIOS_DATE (BIOS_DATE_MONTH "/" \ + BIOS_DATE_DAY "/" \ + BIOS_DATE_YEAR_PREFIX BIOS_DATE_YEAR) +#define BIOS_DATE_SHORT (BIOS_DATE_MONTH "/" \ + BIOS_DATE_DAY "/" \ + BIOS_DATE_YEAR) + // Various memory addresses used by the code. #define BUILD_STACK_ADDR 0x7000 #define BUILD_S3RESUME_STACK_ADDR 0x1000 diff --git a/src/fw/biostables.c b/src/fw/biostables.c index fe8626ef..b055c9b2 100644 --- a/src/fw/biostables.c +++ b/src/fw/biostables.c @@ -401,7 +401,6 @@ smbios_new_type_0(void *start, }
#define BIOS_NAME "SeaBIOS" -#define BIOS_DATE "04/01/2014"
static int smbios_romfile_setup(void) diff --git a/src/fw/smbios.c b/src/fw/smbios.c index 62a563b2..96104714 100644 --- a/src/fw/smbios.c +++ b/src/fw/smbios.c @@ -161,7 +161,6 @@ get_external(int type, char **p, unsigned *nr_structs, } while (0)
/* Type 0 -- BIOS Information */ -#define RELEASE_DATE_STR "01/01/2011" static void * smbios_init_type_0(void *start) { @@ -179,7 +178,7 @@ smbios_init_type_0(void *start)
p->bios_starting_address_segment = 0xe800;
- load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR); + load_str_field_with_default(0, bios_release_date_str, BIOS_DATE);
p->bios_rom_size = 0; /* FIXME */
diff --git a/src/misc.c b/src/misc.c index b5117304..189d487b 100644 --- a/src/misc.c +++ b/src/misc.c @@ -174,7 +174,7 @@ struct descloc_s rombios32_gdt_48 VARFSEG = { ****************************************************************/
// BIOS build date -char BiosDate[] VARFSEGFIXED(0xfff5) = "06/23/99"; +char BiosDate[] VARFSEGFIXED(0xfff5) = BIOS_DATE_SHORT;
u8 BiosModelId VARFSEGFIXED(0xfffe) = BUILD_MODEL_ID;
From: Liran Alon liran.alon@oracle.com
We find all the places which cause BIOS_DATE to appear in the data section and remove them - leaving the only place to contain the contents of BIOS_DATE to be BiosDate at FSEG(0xfff5).
We do this by removing the usages of BIOS_DATE and by changing strlen(BIOS_DATE) to sizeof(BIOS_DATE) which works at the preprocessing step - removing the need to add BIOS_DATE as a string in the data section.
We will use the fact that BiosDate is now the only place in FSEG containing the date in the next commit.
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@oracle.com --- src/fw/biostables.c | 14 +++++++++++--- src/util.h | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/fw/biostables.c b/src/fw/biostables.c index b055c9b2..546e83c6 100644 --- a/src/fw/biostables.c +++ b/src/fw/biostables.c @@ -439,7 +439,7 @@ smbios_romfile_setup(void) if (need_t0) { /* common case: add our own type 0, with 3 strings and 4 '\0's */ u16 t0_len = sizeof(struct smbios_type_0) + strlen(BIOS_NAME) + - strlen(VERSION) + strlen(BIOS_DATE) + 4; + strlen(VERSION) + sizeof(BIOS_DATE) + 3; ep.structure_table_length += t0_len; if (t0_len > ep.max_structure_size) ep.max_structure_size = t0_len; @@ -459,8 +459,16 @@ smbios_romfile_setup(void) ep.structure_table_address = (u32)tables;
/* populate final blob */ - if (need_t0) - tables = smbios_new_type_0(tables, BIOS_NAME, VERSION, BIOS_DATE); + if (need_t0) { + char bios_date[sizeof(BIOS_DATE)]; + memcpy(bios_date, BiosDate, sizeof("mm/dd/") - 1); + memcpy(bios_date + sizeof("mm/dd/") - 1, BIOS_DATE_YEAR_PREFIX, + sizeof("yy") - 1); + memcpy(bios_date + sizeof("mm/dd/yy") - 1, + BiosDate + sizeof("mm/dd/") - 1, + sizeof("yy")); + tables = smbios_new_type_0(tables, BIOS_NAME, VERSION, bios_date); + } memcpy(tables, qtables, qtables_len); free(qtables);
diff --git a/src/util.h b/src/util.h index 6dd080f6..68ba848d 100644 --- a/src/util.h +++ b/src/util.h @@ -2,6 +2,7 @@ #ifndef __UTIL_H #define __UTIL_H
+#include "config.h" // BIOS_DATE_SHORT #include "types.h" // u32
// apm.c @@ -243,6 +244,9 @@ void lpt_setup(void); // version.c extern const char VERSION[], BUILDINFO[];
+// misc.c +extern char BiosDate[sizeof(BIOS_DATE_SHORT)] __aligned(1); + // vgahooks.c void handle_155f(struct bregs *regs); void handle_157f(struct bregs *regs);
From: Liran Alon liran.alon@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.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@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;
Check that only one bios date appears in the final ROM.
The check simulates nt!CmpGetBiosDate() in order to ensure that Windows sees the correct date.
For reference implementation of nt!CmpGetBiosDate(), see ReactOS: https://doxygen.reactos.org/d5/dd2/i386_2cmhardwr_8c.html
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@oracle.com --- scripts/checkrom.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/scripts/checkrom.py b/scripts/checkrom.py index aced5e2c..98cdfa7f 100755 --- a/scripts/checkrom.py +++ b/scripts/checkrom.py @@ -17,6 +17,23 @@ def checksum(data, start, size, csum): sumbyte = buildrom.checksum(data[start:start+size]) return subst(data, start+csum, sumbyte)
+def check_windows_bios_date(rawdata): + dates = [] + for i in xrange(len(rawdata)): + if (rawdata[i+0:i+2].isdigit() and + rawdata[i+2] == '/' and + rawdata[i+3:i+5].isdigit() and + rawdata[i+5] == '/' and + rawdata[i+6:i+8].isdigit()): + dates.append(rawdata[i:i+8]) + if len(dates) > 1: + print("Warning! More than one date was detected in rom.") + print(" This may cause Windows OS to report incorrect date:") + print(" %s" % (dates, )) + if len(dates) == 0: + print("Warning! No dates were detected in rom.") + print(" This may cause Windows OS to report incorrect date.") + def main(): # Get args objinfo, finalsize, rawfile, outfile = sys.argv[1:] @@ -46,6 +63,8 @@ def main(): sys.exit(1)
# Sanity checks + check_windows_bios_date(rawdata) + start = symbols['code32flat_start'].offset end = symbols['code32flat_end'].offset expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
From: Liran Alon liran.alon@oracle.com
This is a workaround for the Windows kernel wrongly extracting SystemBiosVersion.
Windows kernel extracts various BIOS information at boot-time. The method it use to extract SystemBiosVersion is very hueristic. It is done by nt!CmpGetBiosVersion().
nt!CmpGetBiosVersion() works by scanning all BIOS memory from 0xF0000 to 0xFFFFF in search for a string of the form x.y where x & y are digits. When it finds such a string, it goes a bunch of characters backwards until an unknown character is reached, checks whether the string contains any of "v 0", "v 1", "Rev ", etc... if it does - a match was found. It then continues to find the next matches.
In our case, this lead to a debug-print string "Intel IGD BDSM enabled at 0x%08x, size %lldMB, dev 00:02.0" to be treated as BIOS version (Because of "2.0" at the end, and the "v 0" contained in it).
This can be seen by: * Typing "wmic bios get biosversion" in CMD * Reading "HKLM\HARDWARE\DESCRIPTION\System" "SystemBiosVersion"
Therefore, this commit solves the issue by just creating the "00:02.0" string dynamically, like in the rest of the file.
For reference implementation of nt!CmpGetBiosVersion(), see ReactOS: https://doxygen.reactos.org/d5/dd2/i386_2cmhardwr_8c.html
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@oracle.com --- src/fw/pciinit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index c0634bcb..5b934d10 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -328,7 +328,8 @@ static void intel_igd_setup(struct pci_device *dev, void *arg) pci_config_writel(bdf, 0x5C, cpu_to_le32((u32)addr));
dprintf(1, "Intel IGD BDSM enabled at 0x%08x, size %lldMB, dev " - "00:02.0\n", (u32)addr, bdsm_size >> 20); + "%02x:%02x.%x\n", (u32)addr, bdsm_size >> 20, + 0, 2, 0); } }
Check that no version string appear in the final ROM.
The check simulates nt!CmpGetBiosVersion() in order to ensure that Windows sees the correct versions.
For reference implementation of nt!CmpGetBiosVersion(), see ReactOS: https://doxygen.reactos.org/d5/dd2/i386_2cmhardwr_8c.html
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Reviewed-by: Arbel Moshe arbel.moshe@oracle.com Signed-off-by: Sam Eiderman shmuel.eiderman@oracle.com Signed-off-by: Liran Alon liran.alon@oracle.com --- scripts/checkrom.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/scripts/checkrom.py b/scripts/checkrom.py index 98cdfa7f..a09203fe 100755 --- a/scripts/checkrom.py +++ b/scripts/checkrom.py @@ -34,6 +34,31 @@ def check_windows_bios_date(rawdata): print("Warning! No dates were detected in rom.") print(" This may cause Windows OS to report incorrect date.")
+def check_windows_bios_version(rawdata): + versions = [] + for i in xrange(len(rawdata)): + if (rawdata[i+0].isdigit() and + rawdata[i+1] == '.' and + rawdata[i+2].isdigit()): + p = i-1 + while ((p >= 0) and (p > i+2-127) + and ord(rawdata[p]) >= ord(' ') + and rawdata[p] != '$'): + p -= 1 + version = rawdata[p+1:i+3] + for s in ["Ver", "Rev", "Rel", + "v0", "v1", "v2", "v3", "v4", + "v5", "v6", "v7", "v8", "v9", + "v 0", "v 1", "v 2", "v 3", "v 4", + "v 5", "v 6", "v 7", "v 8", "v 9"]: + if s in version: + versions.append((rawdata[p+1:i+3], i)) + break + if len(versions) > 0: + print("Warning! Version strings were detected in rom.") + print(" This may cause Windows OS to report incorrect version:") + print(" %s" % (versions, )) + def main(): # Get args objinfo, finalsize, rawfile, outfile = sys.argv[1:] @@ -64,6 +89,7 @@ def main():
# Sanity checks check_windows_bios_date(rawdata) + check_windows_bios_version(rawdata)
start = symbols['code32flat_start'].offset end = symbols['code32flat_end'].offset