This patch set addresses bug 11908, bug 44305, and others. It reconstructs the SMBIOS table from the SMBIOS values that the kernel exposes to userspace.
Because some BIOSes have more than one of each type of SMBIOS struct, and not every BIOS has every type of struct, I have chosen to declare each struct separately. This will allow for a more sophisticated implementation in the future. It will also allow implementations for other platforms (e.g. Mac OS) to implement one or two of the structs without having to implement them all at once.
Testing on Windows revealed that the id parameter to GetSystemFirmwareTable is ignored if the provider parameter is RSMB.
For more information, see the SMBIOS specification: https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.p...
Alex Henrie (4): kernel32: Return BIOS info from GetSystemFirmwareTable on Linux kernel32: Return system info from GetSystemFirmwareTable on Linux kernel32: Return board info from GetSystemFirmwareTable on Linux kernel32: Return chassis info from GetSystemFirmwareTable on Linux
dlls/kernel32/process.c | 294 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 1 deletion(-)
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/kernel32/process.c | 130 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index ff56e9a692..b8df3c40c0 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -81,6 +81,30 @@ typedef struct DWORD dwReserved; } LOADPARMS32;
+#include "pshpack1.h" + +struct smbios_prologue { + unsigned char calling_method; + unsigned char major_version; + unsigned char minor_version; + unsigned char revision; + unsigned long length; +}; + +struct smbios_bios { + unsigned char type; + unsigned char length; + unsigned short handle; + unsigned char manufacturer; + unsigned char version; + unsigned short start; + unsigned char date; + unsigned char size; + unsigned long long characteristics; +}; + +#include "poppack.h" + static DWORD shutdown_flags = 0; static DWORD shutdown_priority = 0x280; static BOOL is_wow64; @@ -102,6 +126,11 @@ const WCHAR *DIR_SysWow64 = NULL; #define PDB32_FILE_APIS_OEM 0x0040 /* File APIs are OEM */ #define PDB32_WIN32S_PROC 0x8000 /* Win32s process */
+/* Firmware table providers */ +#define ACPI 0x41435049 +#define FIRM 0x4649524D +#define RSMB 0x52534D42 + static const WCHAR exeW[] = {'.','e','x','e',0}; static const WCHAR comW[] = {'.','c','o','m',0}; static const WCHAR batW[] = {'.','b','a','t',0}; @@ -4126,12 +4155,111 @@ HRESULT WINAPI UnregisterApplicationRestart(void) return S_OK; }
+static inline void copy_smbios_string(void **buffer, char *string, size_t string_size) +{ + if (!string) return; + strcpy(*buffer, string); + *buffer = (char*)(*buffer) + string_size; +} + +#ifdef linux +static char* get_smbios_string(const char *path, size_t *string_size) +{ + FILE *file = fopen(path, "r"); + char *ret = NULL; + *string_size = 0; + if (file) + { + *string_size = getline(&ret, string_size, file) + 1; + fclose(file); + if (*string_size >= 2 && ret[*string_size - 2] == '\n') + { + ret[*string_size - 2] = 0; + (*string_size)--; + } + if (*string_size == 1) + { + free(ret); + ret = NULL; + *string_size = 0; + } + } + return ret; +} +#endif + /*********************************************************************** * GetSystemFirmwareTable (KERNEL32.@) */ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD size) { - FIXME("(%d %d %p %d):stub\n", provider, id, buffer, size); + FIXME("(%08x %08x %p %d): semi-stub\n", provider, id, buffer, size); + switch (provider) + { + case RSMB: + { +#ifdef linux + char *bios_manufacturer, *bios_version, *bios_date; + size_t bios_manufacturer_size, bios_version_size, bios_date_size; + size_t required_size = sizeof(struct smbios_prologue); + unsigned char string_count; + struct smbios_prologue *prologue; + struct smbios_bios *bios; + + bios_manufacturer = get_smbios_string("/sys/class/dmi/id/bios_vendor", &bios_manufacturer_size); + bios_version = get_smbios_string("/sys/class/dmi/id/bios_version", &bios_version_size); + bios_date = get_smbios_string("/sys/class/dmi/id/bios_date", &bios_date_size); + + required_size += sizeof(struct smbios_bios); + if (!bios_manufacturer_size && !bios_version_size && !bios_date_size) + required_size += 2; + else + required_size += bios_manufacturer_size + bios_version_size + bios_date_size + 1; + + if (required_size > size) + return required_size; + + prologue = (struct smbios_prologue*)buffer; + prologue->calling_method = 0; + prologue->major_version = 2; + prologue->minor_version = 0; + prologue->revision = 0; + prologue->length = required_size - sizeof(struct smbios_prologue); + buffer = (char*)buffer + sizeof(struct smbios_prologue); + + string_count = 0; + bios = (struct smbios_bios*)buffer; + bios->type = 0; + bios->length = sizeof(struct smbios_bios); + bios->handle = 0; + bios->manufacturer = bios_manufacturer ? ++string_count : 0; + bios->version = bios_version ? ++string_count : 0; + bios->start = 0; + bios->date = bios_date ? ++string_count : 0; + bios->size = 0; + bios->characteristics = 0x4; /* not supported */ + buffer = (char*)buffer + sizeof(struct smbios_bios); + + if (!bios_manufacturer && !bios_version && !bios_date) + { + memset(buffer, 0, 2); + } + else + { + copy_smbios_string(&buffer, bios_manufacturer, bios_manufacturer_size); + copy_smbios_string(&buffer, bios_version, bios_version_size); + copy_smbios_string(&buffer, bios_date, bios_date_size); + memset(buffer, 0, 1); + } + + free(bios_manufacturer); + free(bios_version); + free(bios_date); + + return required_size; +#endif + } + } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; }
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/kernel32/process.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index b8df3c40c0..689f6d730c 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -103,6 +103,16 @@ struct smbios_bios { unsigned long long characteristics; };
+struct smbios_system { + unsigned char type; + unsigned char length; + unsigned short handle; + unsigned char manufacturer; + unsigned char product; + unsigned char version; + unsigned char serial; +}; + #include "poppack.h"
static DWORD shutdown_flags = 0; @@ -4201,14 +4211,21 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD #ifdef linux char *bios_manufacturer, *bios_version, *bios_date; size_t bios_manufacturer_size, bios_version_size, bios_date_size; + char *system_manufacturer, *system_product, *system_version, *system_serial; + size_t system_manufacturer_size, system_product_size, system_version_size, system_serial_size; size_t required_size = sizeof(struct smbios_prologue); unsigned char string_count; struct smbios_prologue *prologue; struct smbios_bios *bios; + struct smbios_system *system;
bios_manufacturer = get_smbios_string("/sys/class/dmi/id/bios_vendor", &bios_manufacturer_size); bios_version = get_smbios_string("/sys/class/dmi/id/bios_version", &bios_version_size); bios_date = get_smbios_string("/sys/class/dmi/id/bios_date", &bios_date_size); + system_manufacturer = get_smbios_string("/sys/class/dmi/id/sys_vendor", &system_manufacturer_size); + system_product = get_smbios_string("/sys/class/dmi/id/product", &system_product_size); + system_version = get_smbios_string("/sys/class/dmi/id/product_version", &system_version_size); + system_serial = get_smbios_string("/sys/class/dmi/id/product_serial", &system_serial_size);
required_size += sizeof(struct smbios_bios); if (!bios_manufacturer_size && !bios_version_size && !bios_date_size) @@ -4216,6 +4233,13 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD else required_size += bios_manufacturer_size + bios_version_size + bios_date_size + 1;
+ required_size += sizeof(struct smbios_system); + if (!system_manufacturer_size && !system_product_size && !system_version_size && !system_serial_size) + required_size += 2; + else + required_size += system_manufacturer_size + system_product_size + system_version_size + + system_serial_size + 1; + if (required_size > size) return required_size;
@@ -4243,6 +4267,7 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD if (!bios_manufacturer && !bios_version && !bios_date) { memset(buffer, 0, 2); + buffer = (char*)buffer + 2; } else { @@ -4250,11 +4275,40 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD copy_smbios_string(&buffer, bios_version, bios_version_size); copy_smbios_string(&buffer, bios_date, bios_date_size); memset(buffer, 0, 1); + buffer = (char*)buffer + 1; + } + + string_count = 0; + system = (struct smbios_system*)buffer; + system->type = 1; + system->length = sizeof(struct smbios_system); + system->handle = 0; + system->manufacturer = system_manufacturer ? ++string_count : 0; + system->product = system_product ? ++string_count : 0; + system->version = system_version ? ++string_count : 0; + system->serial = system_serial ? ++string_count : 0; + buffer = (char*)buffer + sizeof(struct smbios_system); + + if (!system_manufacturer && !system_product && !system_version && !system_serial) + { + memset(buffer, 0, 2); + } + else + { + copy_smbios_string(&buffer, system_manufacturer, system_manufacturer_size); + copy_smbios_string(&buffer, system_product, system_product_size); + copy_smbios_string(&buffer, system_version, system_version_size); + copy_smbios_string(&buffer, system_serial, system_serial_size); + memset(buffer, 0, 1); }
free(bios_manufacturer); free(bios_version); free(bios_date); + free(system_manufacturer); + free(system_product); + free(system_version); + free(system_serial);
return required_size; #endif
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/kernel32/process.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 689f6d730c..f31438ef6f 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -113,6 +113,16 @@ struct smbios_system { unsigned char serial; };
+struct smbios_board { + unsigned char type; + unsigned char length; + unsigned short handle; + unsigned char manufacturer; + unsigned char product; + unsigned char version; + unsigned char serial; +}; + #include "poppack.h"
static DWORD shutdown_flags = 0; @@ -4213,11 +4223,14 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD size_t bios_manufacturer_size, bios_version_size, bios_date_size; char *system_manufacturer, *system_product, *system_version, *system_serial; size_t system_manufacturer_size, system_product_size, system_version_size, system_serial_size; + char *board_manufacturer, *board_product, *board_version, *board_serial; + size_t board_manufacturer_size, board_product_size, board_version_size, board_serial_size; size_t required_size = sizeof(struct smbios_prologue); unsigned char string_count; struct smbios_prologue *prologue; struct smbios_bios *bios; struct smbios_system *system; + struct smbios_board *board;
bios_manufacturer = get_smbios_string("/sys/class/dmi/id/bios_vendor", &bios_manufacturer_size); bios_version = get_smbios_string("/sys/class/dmi/id/bios_version", &bios_version_size); @@ -4226,6 +4239,10 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD system_product = get_smbios_string("/sys/class/dmi/id/product", &system_product_size); system_version = get_smbios_string("/sys/class/dmi/id/product_version", &system_version_size); system_serial = get_smbios_string("/sys/class/dmi/id/product_serial", &system_serial_size); + board_manufacturer = get_smbios_string("/sys/class/dmi/id/board_vendor", &board_manufacturer_size); + board_product = get_smbios_string("/sys/class/dmi/id/board_name", &board_product_size); + board_version = get_smbios_string("/sys/class/dmi/id/board_version", &board_version_size); + board_serial = get_smbios_string("/sys/class/dmi/id/board_serial", &board_serial_size);
required_size += sizeof(struct smbios_bios); if (!bios_manufacturer_size && !bios_version_size && !bios_date_size) @@ -4240,6 +4257,13 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD required_size += system_manufacturer_size + system_product_size + system_version_size + system_serial_size + 1;
+ required_size += sizeof(struct smbios_board); + if (!board_manufacturer_size && !board_product_size && !board_version_size && !board_serial_size) + required_size += 2; + else + required_size += board_manufacturer_size + board_product_size + board_version_size + + board_serial_size + 1; + if (required_size > size) return required_size;
@@ -4292,6 +4316,7 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD if (!system_manufacturer && !system_product && !system_version && !system_serial) { memset(buffer, 0, 2); + buffer = (char*)buffer + 2; } else { @@ -4300,6 +4325,31 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD copy_smbios_string(&buffer, system_version, system_version_size); copy_smbios_string(&buffer, system_serial, system_serial_size); memset(buffer, 0, 1); + buffer = (char*)buffer + 1; + } + + string_count = 0; + board = (struct smbios_board*)buffer; + board->type = 2; + board->length = sizeof(struct smbios_board); + board->handle = 0; + board->manufacturer = board_manufacturer ? ++string_count : 0; + board->product = board_product ? ++string_count : 0; + board->version = board_version ? ++string_count : 0; + board->serial = board_serial ? ++string_count : 0; + buffer = (char*)buffer + sizeof(struct smbios_board); + + if (!board_manufacturer && !board_product && !board_version && !board_serial) + { + memset(buffer, 0, 2); + } + else + { + copy_smbios_string(&buffer, board_manufacturer, board_manufacturer_size); + copy_smbios_string(&buffer, board_product, board_product_size); + copy_smbios_string(&buffer, board_version, board_version_size); + copy_smbios_string(&buffer, board_serial, board_serial_size); + memset(buffer, 0, 1); }
free(bios_manufacturer); @@ -4309,6 +4359,10 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD free(system_product); free(system_version); free(system_serial); + free(board_manufacturer); + free(board_product); + free(board_version); + free(board_serial);
return required_size; #endif
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- dlls/kernel32/process.c | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index f31438ef6f..c81cc54a56 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -123,6 +123,17 @@ struct smbios_board { unsigned char serial; };
+struct smbios_chassis { + unsigned char type; + unsigned char length; + unsigned short handle; + unsigned char manufacturer; + unsigned char shape; + unsigned char version; + unsigned char serial; + unsigned char asset_tag; +}; + #include "poppack.h"
static DWORD shutdown_flags = 0; @@ -4225,12 +4236,15 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD size_t system_manufacturer_size, system_product_size, system_version_size, system_serial_size; char *board_manufacturer, *board_product, *board_version, *board_serial; size_t board_manufacturer_size, board_product_size, board_version_size, board_serial_size; + char *chassis_manufacturer, *chassis_version, *chassis_serial, *chassis_asset_tag; + size_t chassis_manufacturer_size, chassis_version_size, chassis_serial_size, chassis_asset_tag_size; size_t required_size = sizeof(struct smbios_prologue); unsigned char string_count; struct smbios_prologue *prologue; struct smbios_bios *bios; struct smbios_system *system; struct smbios_board *board; + struct smbios_chassis *chassis;
bios_manufacturer = get_smbios_string("/sys/class/dmi/id/bios_vendor", &bios_manufacturer_size); bios_version = get_smbios_string("/sys/class/dmi/id/bios_version", &bios_version_size); @@ -4243,6 +4257,10 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD board_product = get_smbios_string("/sys/class/dmi/id/board_name", &board_product_size); board_version = get_smbios_string("/sys/class/dmi/id/board_version", &board_version_size); board_serial = get_smbios_string("/sys/class/dmi/id/board_serial", &board_serial_size); + chassis_manufacturer = get_smbios_string("/sys/class/dmi/id/chassis_vendor", &chassis_manufacturer_size); + chassis_version = get_smbios_string("/sys/class/dmi/id/chassis_version", &chassis_version_size); + chassis_serial = get_smbios_string("/sys/class/dmi/id/chassis_serial", &chassis_serial_size); + chassis_asset_tag = get_smbios_string("/sys/class/dmi/id/chassis_tag", &chassis_asset_tag_size);
required_size += sizeof(struct smbios_bios); if (!bios_manufacturer_size && !bios_version_size && !bios_date_size) @@ -4264,6 +4282,13 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD required_size += board_manufacturer_size + board_product_size + board_version_size + board_serial_size + 1;
+ required_size += sizeof(struct smbios_chassis); + if (!chassis_manufacturer_size && !chassis_version_size && !chassis_serial_size && !chassis_asset_tag_size) + required_size += 2; + else + required_size += chassis_manufacturer_size + chassis_version_size + chassis_serial_size + + chassis_asset_tag_size + 1; + if (required_size > size) return required_size;
@@ -4342,6 +4367,7 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD if (!board_manufacturer && !board_product && !board_version && !board_serial) { memset(buffer, 0, 2); + buffer = (char*)buffer + 2; } else { @@ -4350,6 +4376,32 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD copy_smbios_string(&buffer, board_version, board_version_size); copy_smbios_string(&buffer, board_serial, board_serial_size); memset(buffer, 0, 1); + buffer = (char*)buffer + 1; + } + + string_count = 0; + chassis = (struct smbios_chassis*)buffer; + chassis->type = 3; + chassis->length = sizeof(struct smbios_chassis); + chassis->handle = 0; + chassis->manufacturer = chassis_manufacturer ? ++string_count : 0; + chassis->shape = 0x2; /* unknown */ + chassis->version = chassis_version ? ++string_count : 0; + chassis->serial = chassis_serial ? ++string_count : 0; + chassis->asset_tag = chassis_asset_tag ? ++string_count : 0; + buffer = (char*)buffer + sizeof(struct smbios_chassis); + + if (!chassis_manufacturer && !chassis_version && !chassis_serial && !chassis_asset_tag) + { + memset(buffer, 0, 2); + } + else + { + copy_smbios_string(&buffer, chassis_manufacturer, chassis_manufacturer_size); + copy_smbios_string(&buffer, chassis_version, chassis_version_size); + copy_smbios_string(&buffer, chassis_serial, chassis_serial_size); + copy_smbios_string(&buffer, chassis_asset_tag, chassis_asset_tag_size); + memset(buffer, 0, 1); }
free(bios_manufacturer); @@ -4363,6 +4415,10 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, PVOID buffer, DWORD free(board_product); free(board_version); free(board_serial); + free(chassis_manufacturer); + free(chassis_version); + free(chassis_serial); + free(chassis_asset_tag);
return required_size; #endif