[PATCH v5 4/8] ntdll: Return BIOS info from NtQuerySystemInformation on Linux
Alex Henrie
alexhenrie24 at gmail.com
Fri Jun 15 01:59:10 CDT 2018
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
dlls/ntdll/nt.c | 174 ++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/info.c | 14 ++--
2 files changed, 182 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index dc0ce04f42..658970b051 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -66,6 +66,35 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+#include "pshpack1.h"
+
+struct smbios_prologue {
+ BYTE calling_method;
+ BYTE major_version;
+ BYTE minor_version;
+ BYTE revision;
+ DWORD length;
+};
+
+struct smbios_bios {
+ BYTE type;
+ BYTE length;
+ WORD handle;
+ BYTE vendor;
+ BYTE version;
+ WORD start;
+ BYTE date;
+ BYTE size;
+ UINT64 characteristics;
+};
+
+#include "poppack.h"
+
+/* Firmware table providers */
+#define ACPI 0x41435049
+#define FIRM 0x4649524D
+#define RSMB 0x52534D42
+
/*
* Token
*/
@@ -1850,6 +1879,129 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
}
#endif
+static inline void copy_smbios_string(char **buffer, char *string, size_t string_size)
+{
+ if (!string) return;
+ strcpy(*buffer, string);
+ *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;
+}
+
+static inline NTSTATUS get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti,
+ ULONG available_len, ULONG *required_len)
+{
+ switch (sfti->ProviderSignature)
+ {
+ case RSMB:
+ {
+ char *bios_vendor, *bios_version, *bios_date;
+ size_t bios_vendor_size, bios_version_size, bios_date_size;
+ char *buffer = (char*)sfti->TableBuffer;
+ BYTE string_count;
+ struct smbios_prologue *prologue;
+ struct smbios_bios *bios;
+
+ bios_vendor = get_smbios_string("/sys/class/dmi/id/bios_vendor", &bios_vendor_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_len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
+
+ *required_len += sizeof(struct smbios_prologue);
+
+ *required_len += sizeof(struct smbios_bios);
+ *required_len += max(bios_vendor_size + bios_version_size + bios_date_size + 1, 2);
+
+ if (available_len < *required_len)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ sfti->TableBufferLength = *required_len - FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
+
+ prologue = (struct smbios_prologue*)buffer;
+ prologue->calling_method = 0;
+ prologue->major_version = 2;
+ prologue->minor_version = 0;
+ prologue->revision = 0;
+ prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
+ 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->vendor = bios_vendor ? ++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 += sizeof(struct smbios_bios);
+
+ if (string_count)
+ {
+ copy_smbios_string(&buffer, bios_vendor, bios_vendor_size);
+ copy_smbios_string(&buffer, bios_version, bios_version_size);
+ copy_smbios_string(&buffer, bios_date, bios_date_size);
+ memset(buffer, 0, 1);
+ }
+ else
+ {
+ memset(buffer, 0, 2);
+ }
+
+ free(bios_vendor);
+ free(bios_version);
+ free(bios_date);
+
+ return STATUS_SUCCESS;
+ }
+ default:
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
+ }
+ }
+}
+
+#else
+
+static inline NTSTATUS get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti,
+ ULONG available_len, ULONG *required_len)
+{
+ return STATUS_NOT_IMPLEMENTED;
+ FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
+}
+
+#endif
+
/******************************************************************************
* NtQuerySystemInformation [NTDLL.@]
* ZwQuerySystemInformation [NTDLL.@]
@@ -2359,6 +2511,28 @@ NTSTATUS WINAPI NtQuerySystemInformation(
else ret = STATUS_INFO_LENGTH_MISMATCH;
}
break;
+ case SystemFirmwareTableInformation:
+ {
+ SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = (SYSTEM_FIRMWARE_TABLE_INFORMATION*)SystemInformation;
+ len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
+ if (Length < len)
+ {
+ ret = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ switch (sfti->Action)
+ {
+ case SystemFirmwareTable_Get:
+ ret = get_firmware_info(sfti, Length, &len);
+ break;
+ default:
+ len = 0;
+ ret = STATUS_NOT_IMPLEMENTED;
+ FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
+ }
+ }
+ break;
default:
FIXME("(0x%08x,%p,0x%08x,%p) stub\n",
SystemInformationClass,SystemInformation,Length,ResultLength);
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index cdb91e1b73..b8feebd474 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -59,6 +59,12 @@ static DWORD one_before_last_pid = 0;
#define FIRM 0x4649524D
#define RSMB 0x52534D42
+#ifdef linux
+static const int firmware_todo = 0;
+#else
+static const int firmware_todo = 1;
+#endif
+
static BOOL InitFunctionPtrs(void)
{
/* All needed functions are NT based, so using GetModuleHandle is a good check */
@@ -840,13 +846,10 @@ static void test_query_firmware(void)
ok(!!sfti, "Failed to allocate memory\n");
status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, 15, &len1);
-todo_wine
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
-todo_wine
ok(len1 == 16, "Expected length 16, got %u\n", len1);
status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, 16, &len1);
-todo_wine
ok(status == STATUS_NOT_IMPLEMENTED, "Expected STATUS_NOT_IMPLEMENTED, got %08x\n", status);
ok(len1 == 0, "Expected length 0, got %u\n", len1);
@@ -854,16 +857,15 @@ todo_wine
sfti->Action = SystemFirmwareTable_Get;
status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, 16, &len1);
-todo_wine
+todo_wine_if(firmware_todo)
ok(status == STATUS_BUFFER_TOO_SMALL, "Expected STATUS_BUFFER_TOO_SMALL, got %08x\n", status);
-todo_wine
ok(len1 >= 16, "Expected length >= 16, got %u\n", len1);
sfti = HeapReAlloc(GetProcessHeap(), 0, sfti, len1);
ok(!!sfti, "Failed to allocate memory\n");
status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, len1, &len2);
-todo_wine
+todo_wine_if(firmware_todo)
ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
ok(len2 == len1, "Expected length %u, got %u\n", len1, len2);
--
2.17.1
More information about the wine-devel
mailing list