Signed-off-by: Alex Henrie alexhenrie24@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);