On Wed, Jun 20, 2018 at 11:18:48PM -0600, Alex Henrie wrote:
Signed-off-by: Alex Henrie alexhenrie24@gmail.com
dlls/ntdll/nt.c | 171 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/tests/info.c | 11 ++- 2 files changed, 180 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index dc0ce04f42..c46c3cd01d 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,126 @@ static NTSTATUS create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION ** } #endif
+static inline void copy_smbios_string(char **buffer, char *s, size_t len)
This needs to go inside the #ifdef linux
+{
- if (!len) return;
- strcpy(*buffer, s);
Since we're passing the length, this would be better as a memcpy( , , len + 1).
- *buffer += len + 1;
+}
+#ifdef linux
+static size_t get_smbios_string(const char *path, char *str, size_t size) +{
- FILE *file;
- size_t len;
- if (!(file = fopen(path, "r")))
return 0;
- len = fread(str, 1, size - 1, file);
- fclose(file);
- if (len >= 1 && str[len - 1] == '\n')
- {
str[len - 1] = 0;
len--;
- }
- else
- {
str[len] = 0;
- }
This would be cleaner as:
if (len >= 1 && str[len - 1] == '\n') len--;
str[len] = 0;
(basically avoid the code duplication of str[len] = 0).
- return len;
+}
+static inline NTSTATUS get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti,
ULONG available_len, ULONG *required_len)
Don't use inline on this big function. These days compilers are pretty good at this sort of thing anyway.
+{
- 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;
+#define S(s) s, sizeof(s)
bios_vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
bios_version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
bios_date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
+#undef S
*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);
}
I dislike this if block, partly because of the use of memsets and partly because of the code duplication in setting the final '\0'. This looks cleaner to me:
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);
if (!string_count) *buffer++ = 0; *buffer++ = 0;
(Yes, it calls copy_smbios_string() in the string_count == 0 case, but I can live with that for the sake of simpler code).
Obviously this applies to the other patches too.
return STATUS_SUCCESS;
}
- default:
{
FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
Printing the provider signature in the fixme would be a good idea.
return STATUS_NOT_IMPLEMENTED;
}
- }
+}
+#else
+static inline NTSTATUS get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti,
ULONG available_len, ULONG *required_len)
Again, drop the inline.
+{
- FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
- sfti->TableBufferLength = 0;
- return STATUS_NOT_IMPLEMENTED;
+}
+#endif
/******************************************************************************
- NtQuerySystemInformation [NTDLL.@]
- ZwQuerySystemInformation [NTDLL.@]
@@ -2359,6 +2508,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");
Let's print the action here.
}
}
default: FIXME("(0x%08x,%p,0x%08x,%p) stub\n", SystemInformationClass,SystemInformation,Length,ResultLength);break;
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 9e12a013cf..29af0e3d90 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