[PATCH v6 4/8] ntdll: Return BIOS info from NtQuerySystemInformation on Linux

Alex Henrie alexhenrie24 at gmail.com
Mon Jun 18 00:38:10 CDT 2018


Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 dlls/ntdll/nt.c         | 170 ++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/tests/info.c |  11 ++-
 2 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index dc0ce04f42..2a4ef783cd 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,125 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION **
 }
 #endif
 
+static inline void copy_smbios_string(char **buffer, char *s, size_t len)
+{
+    if (!len) return;
+    strcpy(*buffer, s);
+    *buffer += len + 1;
+}
+
+#ifdef linux
+
+static void get_smbios_string(const char *path, char *s, size_t *len)
+{
+    FILE *file = fopen(path, "r");
+    if (!file)
+    {
+        *len = 0;
+        return;
+    }
+
+    *len = fread(s, 1, 127, file);
+    fclose(file);
+
+    if (*len >= 1 && s[*len - 1] == '\n')
+    {
+        s[*len - 1] = 0;
+        (*len)--;
+    }
+    else
+    {
+        s[*len] = 0;
+    }
+}
+
+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[128], bios_version[128], bios_date[128];
+            size_t bios_vendor_len, bios_version_len, bios_date_len;
+            char *buffer = (char*)sfti->TableBuffer;
+            BYTE string_count;
+            struct smbios_prologue *prologue;
+            struct smbios_bios *bios;
+
+            get_smbios_string("/sys/class/dmi/id/bios_vendor", bios_vendor, &bios_vendor_len);
+            get_smbios_string("/sys/class/dmi/id/bios_version", bios_version, &bios_version_len);
+            get_smbios_string("/sys/class/dmi/id/bios_date", bios_date, &bios_date_len);
+
+            *required_len = sizeof(struct smbios_prologue);
+
+            *required_len += sizeof(struct smbios_bios);
+            *required_len += max(bios_vendor_len + bios_version_len + bios_date_len + 4, 2);
+
+            sfti->TableBufferLength = *required_len;
+
+            *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
+
+            if (available_len < *required_len)
+            {
+                return STATUS_BUFFER_TOO_SMALL;
+            }
+
+            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_len ? ++string_count : 0;
+            bios->version = bios_version_len ? ++string_count : 0;
+            bios->start = 0;
+            bios->date = bios_date_len ? ++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_len);
+                copy_smbios_string(&buffer, bios_version, bios_version_len);
+                copy_smbios_string(&buffer, bios_date, bios_date_len);
+                memset(buffer, 0, 1);
+            }
+            else
+            {
+                memset(buffer, 0, 2);
+            }
+
+            return STATUS_SUCCESS;
+        }
+    default:
+        {
+            FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
+            return STATUS_NOT_IMPLEMENTED;
+        }
+    }
+}
+
+#else
+
+static inline NTSTATUS get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti,
+                                         ULONG available_len, ULONG *required_len)
+{
+    FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
+    sfti->TableBufferLength = 0;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+#endif
+
 /******************************************************************************
  * NtQuerySystemInformation [NTDLL.@]
  * ZwQuerySystemInformation [NTDLL.@]
@@ -2359,6 +2507,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 804a0ac902..d1c451157d 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 */
@@ -842,12 +848,11 @@ 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 || broken(status == STATUS_INVALID_INFO_CLASS) /* xp */,
        "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
     if (len1 == 0) /* xp, 2003 */
     {
-        skip("SystemFirmwareTableInformation is not available\n");
+        win_skip("SystemFirmwareTableInformation is not available\n");
         HeapFree(GetProcessHeap(), 0, sfti);
         return;
     }
@@ -862,6 +867,7 @@ todo_wine
     sfti->TableID = 0;
 
     status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, 16, &len1);
+todo_wine_if(firmware_todo)
     ok(status == STATUS_BUFFER_TOO_SMALL, "Expected STATUS_BUFFER_TOO_SMALL, got %08x\n", status);
     ok(len1 >= 16, "Expected length >= 16, got %u\n", len1);
     ok(sfti->TableBufferLength == len1 - 16, "Expected length %u, got %u\n", len1 - 16, sfti->TableBufferLength);
@@ -873,6 +879,7 @@ todo_wine
     {
         sfti->TableID = i;
         status = pNtQuerySystemInformation(SystemFirmwareTableInformation, sfti, len1, &len2);
+todo_wine_if(firmware_todo)
         ok(status == STATUS_SUCCESS, "Table %u: Expected STATUS_SUCCESS, got %08x\n", i, status);
         ok(len2 == len1, "Table %u: Expected length %u, got %u\n", i, len1, len2);
         ok(sfti->TableBufferLength == len1 - 16,
-- 
2.17.1




More information about the wine-devel mailing list