[PATCH v5 4/8] ntdll: Return BIOS info from NtQuerySystemInformation on Linux
Huw Davies
huw at codeweavers.com
Fri Jun 15 03:41:12 CDT 2018
On Fri, Jun 15, 2018 at 12:59:10AM -0600, Alex Henrie wrote:
> 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;
I'm not sure we want to use malloc based functions here.
fgets() using a fixed-size buffer with a sensibly chosen size should
be fine.
> + 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