[PATCH v2] wineboot: Populate BIOS registry keys.

Brendan Shanks bshanks at codeweavers.com
Thu Feb 20 14:50:44 CST 2020


Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
---
Now parses SMBIOS directly instead of using WBEM. Separate patches for
ntdll are in progress to populate more SMBIOS fields (SKU, family) on
Linux.

 programs/wineboot/wineboot.c | 240 +++++++++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)

diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c
index 8e3e234397..6e70f0978c 100644
--- a/programs/wineboot/wineboot.c
+++ b/programs/wineboot/wineboot.c
@@ -187,6 +187,10 @@ static DWORD set_reg_value( HKEY hkey, const WCHAR *name, const WCHAR *value )
 {
     return RegSetValueExW( hkey, name, 0, REG_SZ, (const BYTE *)value, (lstrlenW(value) + 1) * sizeof(WCHAR) );
 }
+static DWORD set_reg_value_dword( HKEY hkey, const WCHAR *name, DWORD value )
+{
+    return RegSetValueExW( hkey, name, 0, REG_DWORD, (const BYTE *)&value, sizeof(value) );
+}
 
 #if defined(__i386__) || defined(__x86_64__)
 
@@ -299,6 +303,239 @@ static void get_namestring( WCHAR *buf ) { }
 
 #endif  /* __i386__ || __x86_64__ */
 
+#include "pshpack1.h"
+struct smbios_prologue
+{
+    BYTE  calling_method;
+    BYTE  major_version;
+    BYTE  minor_version;
+    BYTE  revision;
+    DWORD length;
+};
+
+enum smbios_type
+{
+    SMBIOS_TYPE_BIOS,
+    SMBIOS_TYPE_SYSTEM,
+    SMBIOS_TYPE_BASEBOARD,
+};
+
+struct smbios_header
+{
+    BYTE type;
+    BYTE length;
+    WORD handle;
+};
+
+struct smbios_baseboard
+{
+    struct smbios_header hdr;
+    BYTE                 vendor;
+    BYTE                 product;
+    BYTE                 version;
+    BYTE                 serial;
+};
+
+struct smbios_bios
+{
+    struct smbios_header hdr;
+    BYTE                 vendor;
+    BYTE                 version;
+    WORD                 start;
+    BYTE                 date;
+    BYTE                 size;
+    UINT64               characteristics;
+    BYTE                 characteristics_ext[2];
+    BYTE                 system_bios_major_release;
+    BYTE                 system_bios_minor_release;
+    BYTE                 ec_firmware_major_release;
+    BYTE                 ec_firmware_minor_release;
+};
+
+struct smbios_system
+{
+    struct smbios_header hdr;
+    BYTE                 vendor;
+    BYTE                 product;
+    BYTE                 version;
+    BYTE                 serial;
+    BYTE                 uuid[16];
+    BYTE                 wake_up_type;
+    BYTE                 sku;
+    BYTE                 family;
+};
+#include "poppack.h"
+
+#define RSMB (('R' << 24) | ('S' << 16) | ('M' << 8) | 'B')
+
+static const struct smbios_header *find_smbios_entry( enum smbios_type type, const char *buf, UINT len )
+{
+    const char *ptr, *start;
+    const struct smbios_prologue *prologue;
+    const struct smbios_header *hdr;
+
+    if (len < sizeof(struct smbios_prologue)) return NULL;
+    prologue = (const struct smbios_prologue *)buf;
+    if (prologue->length > len - sizeof(*prologue) || prologue->length < sizeof(*hdr)) return NULL;
+
+    start = (const char *)(prologue + 1);
+    hdr = (const struct smbios_header *)start;
+
+    for (;;)
+    {
+        if ((const char *)hdr - start >= prologue->length - sizeof(*hdr)) return NULL;
+
+        if (!hdr->length)
+        {
+            WARN( "invalid entry\n" );
+            return NULL;
+        }
+
+        if (hdr->type == type)
+        {
+            if ((const char *)hdr - start + hdr->length > prologue->length) return NULL;
+            break;
+        }
+        else /* skip other entries and their strings */
+        {
+            for (ptr = (const char *)hdr + hdr->length; ptr - buf < len && *ptr; ptr++)
+            {
+                for (; ptr - buf < len; ptr++) if (!*ptr) break;
+            }
+            if (ptr == (const char *)hdr + hdr->length) ptr++;
+            hdr = (const struct smbios_header *)(ptr + 1);
+        }
+    }
+
+    return hdr;
+}
+
+static inline WCHAR *heap_strdupAW( const char *src )
+{
+    int len;
+    WCHAR *dst;
+    if (!src) return NULL;
+    len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
+    if ((dst = HeapAlloc( GetProcessHeap(), 0, len * sizeof(*dst) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
+    return dst;
+}
+
+static WCHAR *get_smbios_string( BYTE id, const char *buf, UINT offset, UINT buflen )
+{
+    const char *ptr = buf + offset;
+    UINT i = 0;
+
+    if (!id || offset >= buflen) return NULL;
+    for (ptr = buf + offset; ptr - buf < buflen && *ptr; ptr++)
+    {
+        if (++i == id) return heap_strdupAW( ptr );
+        for (; ptr - buf < buflen; ptr++) if (!*ptr) break;
+    }
+    return NULL;
+}
+
+static void set_value_from_smbios_string( HKEY key, const WCHAR *value, BYTE id, const char *buf, UINT offset, UINT buflen )
+{
+    WCHAR *str;
+    str = get_smbios_string( id, buf, offset, buflen );
+    set_reg_value( key, value, str ? str : L"" );
+    HeapFree( GetProcessHeap(), 0, str );
+}
+
+static void create_bios_baseboard_values( HKEY bios_key, const char *buf, UINT len )
+{
+    const struct smbios_header *hdr;
+    const struct smbios_baseboard *baseboard;
+    UINT offset;
+
+    if (!(hdr = find_smbios_entry( SMBIOS_TYPE_BASEBOARD, buf, len ))) return;
+    baseboard = (const struct smbios_baseboard *)hdr;
+    offset = (const char *)baseboard - buf + baseboard->hdr.length;
+
+    set_value_from_smbios_string( bios_key, L"BaseBoardManufacturer", baseboard->vendor, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"BaseBoardProduct", baseboard->product, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"BaseBoardVersion", baseboard->version, buf, offset, len );
+}
+
+static void create_bios_bios_values( HKEY bios_key, const char *buf, UINT len )
+{
+    const struct smbios_header *hdr;
+    const struct smbios_bios *bios;
+    UINT offset;
+
+    if (!(hdr = find_smbios_entry( SMBIOS_TYPE_BIOS, buf, len ))) return;
+    bios = (const struct smbios_bios *)hdr;
+    offset = (const char *)bios - buf + bios->hdr.length;
+
+    set_value_from_smbios_string( bios_key, L"BIOSVendor", bios->vendor, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"BIOSVersion", bios->version, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"BIOSReleaseDate", bios->date, buf, offset, len );
+
+    if (bios->hdr.length >= 0x18)
+    {
+        set_reg_value_dword( bios_key, L"BiosMajorRelease", bios->system_bios_major_release );
+        set_reg_value_dword( bios_key, L"BiosMinorRelease", bios->system_bios_minor_release );
+        set_reg_value_dword( bios_key, L"ECFirmwareMajorVersion", bios->ec_firmware_major_release );
+        set_reg_value_dword( bios_key, L"ECFirmwareMinorVersion", bios->ec_firmware_minor_release );
+    }
+    else
+    {
+        set_reg_value_dword( bios_key, L"BiosMajorRelease", 0xFF );
+        set_reg_value_dword( bios_key, L"BiosMinorRelease", 0xFF );
+        set_reg_value_dword( bios_key, L"ECFirmwareMajorVersion", 0xFF );
+        set_reg_value_dword( bios_key, L"ECFirmwareMinorVersion", 0xFF );
+    }
+}
+
+static void create_bios_system_values( HKEY bios_key, const char *buf, UINT len )
+{
+    const struct smbios_header *hdr;
+    const struct smbios_system *system;
+    UINT offset;
+
+    if (!(hdr = find_smbios_entry( SMBIOS_TYPE_SYSTEM, buf, len ))) return;
+    system = (const struct smbios_system *)hdr;
+    offset = (const char *)system - buf + system->hdr.length;
+
+    set_value_from_smbios_string( bios_key, L"SystemManufacturer", system->vendor, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"SystemProductName", system->product, buf, offset, len );
+    set_value_from_smbios_string( bios_key, L"SystemVersion", system->version, buf, offset, len );
+
+    if (system->hdr.length >= 0x1B)
+    {
+        set_value_from_smbios_string( bios_key, L"SystemSKU", system->sku, buf, offset, len );
+        set_value_from_smbios_string( bios_key, L"SystemFamily", system->family, buf, offset, len );
+    }
+    else
+    {
+        set_value_from_smbios_string( bios_key, L"SystemSKU", 0, buf, offset, len );
+        set_value_from_smbios_string( bios_key, L"SystemFamily", 0, buf, offset, len );
+    }
+}
+
+static void create_bios_key( HKEY system_key )
+{
+    HKEY bios_key;
+    UINT len;
+    char *buf;
+
+    if (RegCreateKeyExW( system_key, L"BIOS", 0, NULL, REG_OPTION_VOLATILE,
+                         KEY_ALL_ACCESS, NULL, &bios_key, NULL ))
+        return;
+
+    len = GetSystemFirmwareTable( RSMB, 0, NULL, 0 );
+    if (!(buf = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
+    len = GetSystemFirmwareTable( RSMB, 0, buf, len );
+
+    create_bios_baseboard_values( bios_key, buf, len );
+    create_bios_bios_values( bios_key, buf, len );
+    create_bios_system_values( bios_key, buf, len );
+
+done:
+    HeapFree( GetProcessHeap(), 0, buf );
+    RegCloseKey( bios_key );
+}
+
 /* create the volatile hardware registry keys */
 static void create_hardware_registry_keys(void)
 {
@@ -409,6 +646,9 @@ static void create_hardware_registry_keys(void)
             RegCloseKey( hkey );
         }
     }
+
+    create_bios_key( system_key );
+
     RegCloseKey( fpu_key );
     RegCloseKey( cpu_key );
     RegCloseKey( system_key );
-- 
2.24.1




More information about the wine-devel mailing list