diff --git a/modules/rostests/apitests/kernel32/CMakeLists.txt b/modules/rostests/apitests/kernel32/CMakeLists.txt index c3290319295..37c5b6adc87 100644 --- a/modules/rostests/apitests/kernel32/CMakeLists.txt +++ b/modules/rostests/apitests/kernel32/CMakeLists.txt @@ -28,6 +28,7 @@ list(APPEND SOURCE SetConsoleWindowInfo.c SetCurrentDirectory.c SetUnhandledExceptionFilter.c + SystemFirmware.c TerminateProcess.c TunnelCache.c WideCharToMultiByte.c diff --git a/modules/rostests/apitests/kernel32/SystemFirmware.c b/modules/rostests/apitests/kernel32/SystemFirmware.c new file mode 100644 index 00000000000..5ba946d8153 --- /dev/null +++ b/modules/rostests/apitests/kernel32/SystemFirmware.c @@ -0,0 +1,466 @@ +/* + * PROJECT: ReactOS API Tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Tests for System Firmware functions + * COPYRIGHT: Copyright 2018 Stanislav Motylkov + */ + +#include "precomp.h" + +static UINT (WINAPI * pEnumSystemFirmwareTables)(DWORD, PVOID, DWORD); +static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, PVOID, DWORD); + +typedef struct ENTRY +{ + DWORD Signature; + DWORD ErrInsuff; + DWORD ErrSuccess; +} ENTRY; + +static +VOID +test_EnumBuffer( + DWORD Signature, + PVOID Buffer, + DWORD dwSize, + UINT * pTableCount, + DWORD * pFirstTableID, + DWORD ErrInsuff, + DWORD ErrSuccess +) +{ + DWORD dwError; + DWORD dwBufferSize; + DWORD dwException; + UINT uResultSize; + + dwException = Buffer && IsBadWritePtr(Buffer, dwSize) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS; + + // Test size = 0 + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = 0; + uResultSize = 0; + StartSeh() + uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(STATUS_SUCCESS); + + if (uResultSize > 0) + { + ok(dwError == ErrInsuff, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrInsuff); + } + else + { + ok(dwError == ErrSuccess, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrSuccess); + } + if (ErrSuccess == ERROR_SUCCESS) + { + ok(uResultSize % sizeof(DWORD) == 0, + "uResultSize is %u, expected %% sizeof(DWORD)\n", + uResultSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + if (Buffer && dwException == STATUS_SUCCESS) + { + ok(*(BYTE *)Buffer == 0xFF, + "Buffer should be clean at offset 0, got %x\n", + *(BYTE *)Buffer); + } + + // Test size = 2 + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = 2; + uResultSize = 0; + StartSeh() + uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(STATUS_SUCCESS); + + if (uResultSize > 0) + { + ok(dwError == ErrInsuff, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrInsuff); + } + else + { + ok(dwError == ErrSuccess, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrSuccess); + } + if (ErrSuccess == ERROR_SUCCESS) + { + ok(uResultSize % sizeof(DWORD) == 0, + "uResultSize is %u, expected %% sizeof(DWORD)\n", + uResultSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + if (Buffer && dwException == STATUS_SUCCESS) + { + ok(*(WORD *)Buffer == 0xFFFF, + "Buffer should be clean at offset 0, got %x\n", + *(WORD *)Buffer); + } + + // Test full size + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + if (uResultSize > 0) + { + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = uResultSize; + uResultSize = 0; + StartSeh() + uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(ErrSuccess == ERROR_SUCCESS ? dwException : STATUS_SUCCESS); + // Windows 7: does not throw exception here + + if (dwException == STATUS_SUCCESS || ErrSuccess == ERROR_INVALID_FUNCTION) + { + ok(dwError == ErrSuccess, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrSuccess); + if (ErrSuccess == ERROR_SUCCESS) + { + ok(uResultSize == dwBufferSize, + "uResultSize is not equal dwBufferSize, expected %ld\n", + dwBufferSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + } + else + { + // Windows 7: returns ERROR_NOACCESS here + ok(dwError == 0xbeeffeed, + "GetLastError() returned %ld, expected %u\n", + dwError, 0xbeeffeed); + // Windows 7: returns correct size here + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + } + + if (pTableCount && pFirstTableID) + { + if (uResultSize > 0) + { + if (Signature == 'RSMB') + { + // Raw SMBIOS have only one table with ID 0 + ok(*(DWORD *)Buffer == 0, + "Buffer should be filled at offset 0, got %lx\n", + *(DWORD *)Buffer); + } + else + { + // In other cases ID can be different + if (ErrSuccess == ERROR_SUCCESS) + { + ok(*(DWORD *)Buffer != 0xFFFFFFFF, + "Buffer should be filled at offset 0\n"); + } + else + { + ok(*(DWORD *)Buffer == 0xFFFFFFFF, + "Buffer should be clean at offset 0\n"); + } + } + } + *pTableCount = uResultSize / sizeof(DWORD); + *pFirstTableID = *(DWORD *)Buffer; + } +} + +static +VOID +test_GetBuffer( + DWORD Signature, + DWORD TableID, + PVOID Buffer, + DWORD dwSize, + BOOL TestFakeID, + DWORD ErrInsuff, + DWORD ErrSuccess +) +{ + DWORD dwError; + DWORD dwBufferSize; + DWORD dwException; + DWORD dwErrCase; + UINT uResultSize; + + dwException = Buffer && IsBadWritePtr(Buffer, dwSize) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS; + switch (Signature) + { + case 'ACPI': + { + dwErrCase = ERROR_NOT_FOUND; + break; + } + case 'FIRM': + { + dwErrCase = ERROR_INVALID_PARAMETER; + break; + } + default: + { + dwErrCase = ErrInsuff; + } + } + + // Test size = 0 + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = 0; + uResultSize = 0; + StartSeh() + uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(STATUS_SUCCESS); + + ok(dwError == (TestFakeID ? dwErrCase : ErrInsuff), + "GetLastError() returned %ld, expected %ld\n", + dwError, (TestFakeID ? dwErrCase : ErrInsuff)); + if (ErrSuccess == ERROR_SUCCESS && (!TestFakeID || dwErrCase == ErrInsuff)) + { + ok(uResultSize > 0, + "uResultSize is %u, expected > 0\n", + uResultSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + if (Buffer && dwException == STATUS_SUCCESS) + { + ok(*(BYTE *)Buffer == 0xFF, + "Buffer should be clean at offset 0, got %x\n", + *(BYTE *)Buffer); + } + + // Test size = 2 + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = 2; + uResultSize = 0; + StartSeh() + uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(STATUS_SUCCESS); + + ok(dwError == (TestFakeID ? dwErrCase : ErrInsuff), + "GetLastError() returned %ld, expected %ld\n", + dwError, (TestFakeID ? dwErrCase : ErrInsuff)); + if (ErrSuccess == ERROR_SUCCESS && (!TestFakeID || dwErrCase == ErrInsuff)) + { + ok(uResultSize > 0, + "uResultSize is %u, expected > 0\n", + uResultSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + if (Buffer && dwException == STATUS_SUCCESS) + { + ok(*(WORD *)Buffer == 0xFFFF, + "Buffer should be clean at offset 0, got %x\n", + *(WORD *)Buffer); + } + + // Test full size + if (Buffer && dwException == STATUS_SUCCESS) + { + FillMemory(Buffer, dwSize, 0xFF); + } + if (uResultSize == 0) + { + return; + } + SetLastError(0xbeeffeed); + dwError = GetLastError(); + dwBufferSize = uResultSize; + uResultSize = 0; + StartSeh() + uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); + dwError = GetLastError(); + EndSeh(ErrSuccess == ERROR_SUCCESS ? dwException : STATUS_SUCCESS); + // Windows 7: does not throw exception here + + if (dwException == STATUS_SUCCESS || ErrSuccess == ERROR_INVALID_FUNCTION) + { + ok(dwError == ErrSuccess, + "GetLastError() returned %ld, expected %ld\n", + dwError, ErrSuccess); + if (ErrSuccess == ERROR_SUCCESS) + { + ok(uResultSize == dwBufferSize, + "uResultSize is not equal dwBufferSize, expected %ld\n", + dwBufferSize); + } + else + { + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + } + else + { + // Windows 7: returns ERROR_NOACCESS here + ok(dwError == 0xbeeffeed, + "GetLastError() returned %ld, expected %u\n", + dwError, 0xbeeffeed); + // Windows 7: returns correct size here + ok(uResultSize == 0, + "uResultSize is %u, expected == 0\n", + uResultSize); + } + + if (Buffer && dwException == STATUS_SUCCESS) + { + if (ErrSuccess == ERROR_SUCCESS) + { + ok(*(DWORD *)Buffer != 0xFFFFFFFF, + "Buffer should be filled at offset 0\n"); + } + else + { + ok(*(DWORD *)Buffer == 0xFFFFFFFF, + "Buffer should be clean at offset 0\n"); + } + } +} + +START_TEST(SystemFirmware) +{ + static const ENTRY Entries[] = + { + { 'ACPI', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, + { 'FIRM', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, + { 'RSMB', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, + /* This entry should be last */ + { 0xDEAD, ERROR_INVALID_FUNCTION, ERROR_INVALID_FUNCTION }, + }; + HANDLE hKernel; + CHAR Buffer[262144]; // 256 KiB should be enough + CHAR Sign[sizeof(DWORD) + 1]; + UINT TableCount[_countof(Entries)]; + DWORD FirstTableID[_countof(Entries)]; + int i; + + hKernel = GetModuleHandleW(L"kernel32.dll"); + if (!hKernel) + { + skip("kernel32.dll module not found. Can't proceed\n"); + return; + } + + pEnumSystemFirmwareTables = (void *)GetProcAddress(hKernel, "EnumSystemFirmwareTables"); + pGetSystemFirmwareTable = (void *)GetProcAddress(hKernel, "GetSystemFirmwareTable"); + + if (!pEnumSystemFirmwareTables) + { + skip("EnumSystemFirmwareTables not found. Can't proceed\n"); + return; + } + if (!pGetSystemFirmwareTable) + { + skip("GetSystemFirmwareTable not found. Can't proceed\n"); + return; + } + + // Test EnumSystemFirmwareTables + for (i = 0; i < _countof(Entries); i++) + { + // Test with NULL buffer + test_EnumBuffer(Entries[i].Signature, NULL, sizeof(Buffer), NULL, NULL, + Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with wrong buffer + test_EnumBuffer(Entries[i].Signature, (PVOID *)0xbeeffeed, sizeof(Buffer), NULL, NULL, + Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with correct buffer + test_EnumBuffer(Entries[i].Signature, &Buffer, sizeof(Buffer), &TableCount[i], &FirstTableID[i], + Entries[i].ErrInsuff, Entries[i].ErrSuccess); + } + + // Test GetSystemFirmwareTable + for (i = 0; i < _countof(Entries); i++) + { + // Test with fake ID and NULL buffer + test_GetBuffer(Entries[i].Signature, 0xbeeffeed, NULL, sizeof(Buffer), + TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with fake ID and wrong buffer + test_GetBuffer(Entries[i].Signature, 0xbeeffeed, (PVOID *)0xbeeffeed, sizeof(Buffer), + TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with fake ID and correct buffer + test_GetBuffer(Entries[i].Signature, 0xbeeffeed, &Buffer, sizeof(Buffer), + TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + if (TableCount[i] == 0) + { + if (i < _countof(Entries) - 1) + { + ZeroMemory(&Sign, sizeof(Sign)); + *(DWORD *)&Sign = _byteswap_ulong(Entries[i].Signature); + skip("No tables for %s found. Skipping\n", + Sign); + } + continue; + } + // Test with correct ID and NULL buffer + test_GetBuffer(Entries[i].Signature, FirstTableID[i], NULL, sizeof(Buffer), + FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with correct ID and wrong buffer + test_GetBuffer(Entries[i].Signature, FirstTableID[i], (PVOID *)0xbeeffeed, sizeof(Buffer), + FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + // Test with correct ID and correct buffer + test_GetBuffer(Entries[i].Signature, FirstTableID[i], &Buffer, sizeof(Buffer), + FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); + } +} diff --git a/modules/rostests/apitests/kernel32/testlist.c b/modules/rostests/apitests/kernel32/testlist.c index 0bf5e424dc0..6364cab8042 100644 --- a/modules/rostests/apitests/kernel32/testlist.c +++ b/modules/rostests/apitests/kernel32/testlist.c @@ -27,6 +27,7 @@ extern void func_PrivMoveFileIdentityW(void); extern void func_SetConsoleWindowInfo(void); extern void func_SetCurrentDirectory(void); extern void func_SetUnhandledExceptionFilter(void); +extern void func_SystemFirmware(void); extern void func_TerminateProcess(void); extern void func_TunnelCache(void); extern void func_WideCharToMultiByte(void); @@ -57,6 +58,7 @@ const struct test winetest_testlist[] = { "SetConsoleWindowInfo", func_SetConsoleWindowInfo }, { "SetCurrentDirectory", func_SetCurrentDirectory }, { "SetUnhandledExceptionFilter", func_SetUnhandledExceptionFilter }, + { "SystemFirmware", func_SystemFirmware }, { "TerminateProcess", func_TerminateProcess }, { "TunnelCache", func_TunnelCache }, { "WideCharToMultiByte", func_WideCharToMultiByte },