1 /* 2 * PROJECT: ReactOS API Tests 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Tests for System Firmware functions 5 * COPYRIGHT: Copyright 2018 Stanislav Motylkov 6 * Copyright 2018 Mark Jansen 7 */ 8 9 #include "precomp.h" 10 11 #include <pseh/pseh2.h> 12 13 static UINT (WINAPI * pEnumSystemFirmwareTables)(DWORD, PVOID, DWORD); 14 static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, PVOID, DWORD); 15 16 typedef struct ENTRY 17 { 18 DWORD Signature; 19 DWORD ErrInsuff; 20 DWORD ErrSuccess; 21 } ENTRY; 22 23 static UINT 24 CallNt(IN DWORD FirmwareTableProviderSignature, 25 IN DWORD FirmwareTableID, 26 OUT PVOID pFirmwareTableBuffer, 27 IN DWORD BufferSize, 28 IN SYSTEM_FIRMWARE_TABLE_ACTION Action) 29 { 30 SYSTEM_FIRMWARE_TABLE_INFORMATION* SysFirmwareInfo; 31 ULONG Result = 0, ReturnedSize; 32 ULONG TotalSize = BufferSize + sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION); 33 NTSTATUS Status; 34 35 SysFirmwareInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TotalSize); 36 if (!SysFirmwareInfo) 37 { 38 SetLastError(ERROR_INVALID_PARAMETER); 39 return 0; 40 } 41 _SEH2_TRY 42 { 43 SysFirmwareInfo->ProviderSignature = FirmwareTableProviderSignature; 44 SysFirmwareInfo->TableID = FirmwareTableID; 45 SysFirmwareInfo->Action = Action; 46 SysFirmwareInfo->TableBufferLength = BufferSize; 47 48 Status = NtQuerySystemInformation(SystemFirmwareTableInformation, SysFirmwareInfo, TotalSize, &ReturnedSize); 49 50 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL) 51 Result = SysFirmwareInfo->TableBufferLength; 52 53 if (NT_SUCCESS(Status) && pFirmwareTableBuffer) 54 { 55 memcpy(pFirmwareTableBuffer, SysFirmwareInfo->TableBuffer, SysFirmwareInfo->TableBufferLength); 56 } 57 } 58 _SEH2_FINALLY 59 { 60 RtlFreeHeap(RtlGetProcessHeap(), 0, SysFirmwareInfo); 61 } 62 _SEH2_END; 63 64 SetLastError(RtlNtStatusToDosError(Status)); 65 return Result; 66 } 67 68 UINT 69 WINAPI 70 fEnumSystemFirmwareTables(IN DWORD FirmwareTableProviderSignature, 71 OUT PVOID pFirmwareTableBuffer, 72 IN DWORD BufferSize) 73 { 74 return CallNt(FirmwareTableProviderSignature, 0, pFirmwareTableBuffer, BufferSize, SystemFirmwareTable_Enumerate); 75 } 76 77 UINT 78 WINAPI 79 fGetSystemFirmwareTable(IN DWORD FirmwareTableProviderSignature, 80 IN DWORD FirmwareTableID, 81 OUT PVOID pFirmwareTableBuffer, 82 IN DWORD BufferSize) 83 { 84 return CallNt(FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize, SystemFirmwareTable_Get); 85 } 86 87 static 88 VOID 89 test_EnumBuffer( 90 DWORD Signature, 91 PVOID Buffer, 92 DWORD dwSize, 93 UINT * pTableCount, 94 DWORD * pFirstTableID, 95 DWORD ErrInsuff, 96 DWORD ErrSuccess 97 ) 98 { 99 DWORD dwError; 100 DWORD dwBufferSize; 101 DWORD dwException; 102 UINT uResultSize; 103 104 dwException = Buffer && IsBadWritePtr(Buffer, dwSize) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS; 105 106 // Test size = 0 107 if (Buffer && dwException == STATUS_SUCCESS) 108 { 109 FillMemory(Buffer, dwSize, 0xFF); 110 } 111 SetLastError(0xbeeffeed); 112 dwError = GetLastError(); 113 dwBufferSize = 0; 114 uResultSize = 0; 115 StartSeh() 116 uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); 117 dwError = GetLastError(); 118 EndSeh(STATUS_SUCCESS); 119 120 if (uResultSize > 0) 121 { 122 ok(dwError == ErrInsuff, 123 "GetLastError() returned %ld, expected %ld\n", 124 dwError, ErrInsuff); 125 } 126 else 127 { 128 ok(dwError == ErrSuccess, 129 "GetLastError() returned %ld, expected %ld\n", 130 dwError, ErrSuccess); 131 } 132 if (ErrSuccess == ERROR_SUCCESS) 133 { 134 ok(uResultSize % sizeof(DWORD) == 0, 135 "uResultSize is %u, expected %% sizeof(DWORD)\n", 136 uResultSize); 137 } 138 else 139 { 140 ok(uResultSize == 0, 141 "uResultSize is %u, expected == 0\n", 142 uResultSize); 143 } 144 if (Buffer && dwException == STATUS_SUCCESS) 145 { 146 ok(*(BYTE *)Buffer == 0xFF, 147 "Buffer should be clean at offset 0, got %x\n", 148 *(BYTE *)Buffer); 149 } 150 151 // Test size = 2 152 if (Buffer && dwException == STATUS_SUCCESS) 153 { 154 FillMemory(Buffer, dwSize, 0xFF); 155 } 156 SetLastError(0xbeeffeed); 157 dwError = GetLastError(); 158 dwBufferSize = 2; 159 uResultSize = 0; 160 StartSeh() 161 uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); 162 dwError = GetLastError(); 163 EndSeh(STATUS_SUCCESS); 164 165 if (uResultSize > 0) 166 { 167 ok(dwError == ErrInsuff, 168 "GetLastError() returned %ld, expected %ld\n", 169 dwError, ErrInsuff); 170 } 171 else 172 { 173 ok(dwError == ErrSuccess, 174 "GetLastError() returned %ld, expected %ld\n", 175 dwError, ErrSuccess); 176 } 177 if (ErrSuccess == ERROR_SUCCESS) 178 { 179 ok(uResultSize % sizeof(DWORD) == 0, 180 "uResultSize is %u, expected %% sizeof(DWORD)\n", 181 uResultSize); 182 } 183 else 184 { 185 ok(uResultSize == 0, 186 "uResultSize is %u, expected == 0\n", 187 uResultSize); 188 } 189 if (Buffer && dwException == STATUS_SUCCESS) 190 { 191 ok(*(WORD *)Buffer == 0xFFFF, 192 "Buffer should be clean at offset 0, got %x\n", 193 *(WORD *)Buffer); 194 } 195 196 // Test full size 197 if (Buffer && dwException == STATUS_SUCCESS) 198 { 199 FillMemory(Buffer, dwSize, 0xFF); 200 } 201 if (uResultSize > 0) 202 { 203 SetLastError(0xbeeffeed); 204 dwError = GetLastError(); 205 dwBufferSize = uResultSize; 206 uResultSize = 0; 207 StartSeh() 208 uResultSize = pEnumSystemFirmwareTables(Signature, Buffer, dwBufferSize); 209 dwError = GetLastError(); 210 EndSeh(ErrSuccess == ERROR_SUCCESS ? dwException : STATUS_SUCCESS); 211 // Windows 7: does not throw exception here 212 213 if (dwException == STATUS_SUCCESS || ErrSuccess == ERROR_INVALID_FUNCTION) 214 { 215 ok(dwError == ErrSuccess, 216 "GetLastError() returned %ld, expected %ld\n", 217 dwError, ErrSuccess); 218 if (ErrSuccess == ERROR_SUCCESS) 219 { 220 ok(uResultSize == dwBufferSize, 221 "uResultSize is not equal dwBufferSize, expected %ld\n", 222 dwBufferSize); 223 } 224 else 225 { 226 ok(uResultSize == 0, 227 "uResultSize is %u, expected == 0\n", 228 uResultSize); 229 } 230 } 231 else 232 { 233 // Windows 7: returns ERROR_NOACCESS here 234 ok(dwError == 0xbeeffeed, 235 "GetLastError() returned %ld, expected %u\n", 236 dwError, 0xbeeffeed); 237 // Windows 7: returns correct size here 238 ok(uResultSize == 0, 239 "uResultSize is %u, expected == 0\n", 240 uResultSize); 241 } 242 } 243 244 if (pTableCount && pFirstTableID) 245 { 246 if (uResultSize > 0) 247 { 248 if (Signature == 'RSMB') 249 { 250 // Raw SMBIOS have only one table with ID 0 251 ok(*(DWORD *)Buffer == 0, 252 "Buffer should be filled at offset 0, got %lx\n", 253 *(DWORD *)Buffer); 254 } 255 else 256 { 257 // In other cases ID can be different 258 if (ErrSuccess == ERROR_SUCCESS) 259 { 260 ok(*(DWORD *)Buffer != 0xFFFFFFFF, 261 "Buffer should be filled at offset 0\n"); 262 } 263 else 264 { 265 ok(*(DWORD *)Buffer == 0xFFFFFFFF, 266 "Buffer should be clean at offset 0\n"); 267 } 268 } 269 } 270 *pTableCount = uResultSize / sizeof(DWORD); 271 *pFirstTableID = *(DWORD *)Buffer; 272 } 273 } 274 275 static 276 VOID 277 test_GetBuffer( 278 DWORD Signature, 279 DWORD TableID, 280 PVOID Buffer, 281 DWORD dwSize, 282 BOOL TestFakeID, 283 DWORD ErrInsuff, 284 DWORD ErrSuccess 285 ) 286 { 287 DWORD dwError; 288 DWORD dwBufferSize; 289 DWORD dwException; 290 DWORD dwErrCase; 291 UINT uResultSize; 292 293 dwException = Buffer && IsBadWritePtr(Buffer, dwSize) ? STATUS_ACCESS_VIOLATION : STATUS_SUCCESS; 294 switch (Signature) 295 { 296 case 'ACPI': 297 { 298 dwErrCase = ERROR_NOT_FOUND; 299 break; 300 } 301 case 'FIRM': 302 { 303 dwErrCase = ERROR_INVALID_PARAMETER; 304 break; 305 } 306 default: 307 { 308 dwErrCase = ErrInsuff; 309 } 310 } 311 312 // Test size = 0 313 if (Buffer && dwException == STATUS_SUCCESS) 314 { 315 FillMemory(Buffer, dwSize, 0xFF); 316 } 317 SetLastError(0xbeeffeed); 318 dwError = GetLastError(); 319 dwBufferSize = 0; 320 uResultSize = 0; 321 StartSeh() 322 uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); 323 dwError = GetLastError(); 324 EndSeh(STATUS_SUCCESS); 325 326 ok(dwError == (TestFakeID ? dwErrCase : ErrInsuff), 327 "GetLastError() returned %ld, expected %ld\n", 328 dwError, (TestFakeID ? dwErrCase : ErrInsuff)); 329 if (ErrSuccess == ERROR_SUCCESS && (!TestFakeID || dwErrCase == ErrInsuff)) 330 { 331 ok(uResultSize > 0, 332 "uResultSize is %u, expected > 0\n", 333 uResultSize); 334 } 335 else 336 { 337 ok(uResultSize == 0, 338 "uResultSize is %u, expected == 0\n", 339 uResultSize); 340 } 341 if (Buffer && dwException == STATUS_SUCCESS) 342 { 343 ok(*(BYTE *)Buffer == 0xFF, 344 "Buffer should be clean at offset 0, got %x\n", 345 *(BYTE *)Buffer); 346 } 347 348 // Test size = 2 349 if (Buffer && dwException == STATUS_SUCCESS) 350 { 351 FillMemory(Buffer, dwSize, 0xFF); 352 } 353 SetLastError(0xbeeffeed); 354 dwError = GetLastError(); 355 dwBufferSize = 2; 356 uResultSize = 0; 357 StartSeh() 358 uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); 359 dwError = GetLastError(); 360 EndSeh(STATUS_SUCCESS); 361 362 ok(dwError == (TestFakeID ? dwErrCase : ErrInsuff), 363 "GetLastError() returned %ld, expected %ld\n", 364 dwError, (TestFakeID ? dwErrCase : ErrInsuff)); 365 if (ErrSuccess == ERROR_SUCCESS && (!TestFakeID || dwErrCase == ErrInsuff)) 366 { 367 ok(uResultSize > 0, 368 "uResultSize is %u, expected > 0\n", 369 uResultSize); 370 } 371 else 372 { 373 ok(uResultSize == 0, 374 "uResultSize is %u, expected == 0\n", 375 uResultSize); 376 } 377 if (Buffer && dwException == STATUS_SUCCESS) 378 { 379 ok(*(WORD *)Buffer == 0xFFFF, 380 "Buffer should be clean at offset 0, got %x\n", 381 *(WORD *)Buffer); 382 } 383 384 // Test full size 385 if (Buffer && dwException == STATUS_SUCCESS) 386 { 387 FillMemory(Buffer, dwSize, 0xFF); 388 } 389 if (uResultSize == 0) 390 { 391 return; 392 } 393 SetLastError(0xbeeffeed); 394 dwError = GetLastError(); 395 dwBufferSize = uResultSize; 396 uResultSize = 0; 397 StartSeh() 398 uResultSize = pGetSystemFirmwareTable(Signature, TableID, Buffer, dwBufferSize); 399 dwError = GetLastError(); 400 EndSeh(ErrSuccess == ERROR_SUCCESS ? dwException : STATUS_SUCCESS); 401 // Windows 7: does not throw exception here 402 403 if (dwException == STATUS_SUCCESS || ErrSuccess == ERROR_INVALID_FUNCTION) 404 { 405 ok(dwError == ErrSuccess, 406 "GetLastError() returned %ld, expected %ld\n", 407 dwError, ErrSuccess); 408 if (ErrSuccess == ERROR_SUCCESS) 409 { 410 ok(uResultSize == dwBufferSize, 411 "uResultSize is not equal dwBufferSize, expected %ld\n", 412 dwBufferSize); 413 } 414 else 415 { 416 ok(uResultSize == 0, 417 "uResultSize is %u, expected == 0\n", 418 uResultSize); 419 } 420 } 421 else 422 { 423 // Windows 7: returns ERROR_NOACCESS here 424 ok(dwError == 0xbeeffeed, 425 "GetLastError() returned %ld, expected %u\n", 426 dwError, 0xbeeffeed); 427 // Windows 7: returns correct size here 428 ok(uResultSize == 0, 429 "uResultSize is %u, expected == 0\n", 430 uResultSize); 431 } 432 433 if (Buffer && dwException == STATUS_SUCCESS) 434 { 435 if (ErrSuccess == ERROR_SUCCESS) 436 { 437 ok(*(DWORD *)Buffer != 0xFFFFFFFF, 438 "Buffer should be filled at offset 0\n"); 439 } 440 else 441 { 442 ok(*(DWORD *)Buffer == 0xFFFFFFFF, 443 "Buffer should be clean at offset 0\n"); 444 } 445 } 446 } 447 448 static 449 VOID 450 test_Functions() 451 { 452 static const ENTRY Entries[] = 453 { 454 { 'ACPI', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, 455 { 'FIRM', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, 456 { 'RSMB', ERROR_INSUFFICIENT_BUFFER, ERROR_SUCCESS }, 457 /* This entry should be last */ 458 { 0xDEAD, ERROR_INVALID_FUNCTION, ERROR_INVALID_FUNCTION }, 459 }; 460 CHAR Buffer[262144]; // 256 KiB should be enough 461 CHAR Sign[sizeof(DWORD) + 1]; 462 UINT TableCount[_countof(Entries)]; 463 DWORD FirstTableID[_countof(Entries)]; 464 int i; 465 466 // Test EnumSystemFirmwareTables 467 for (i = 0; i < _countof(Entries); i++) 468 { 469 // Test with NULL buffer 470 test_EnumBuffer(Entries[i].Signature, NULL, sizeof(Buffer), NULL, NULL, 471 Entries[i].ErrInsuff, Entries[i].ErrSuccess); 472 // Test with wrong buffer 473 test_EnumBuffer(Entries[i].Signature, (PVOID *)(LONG_PTR)0xbeeffeed, sizeof(Buffer), NULL, NULL, 474 Entries[i].ErrInsuff, Entries[i].ErrSuccess); 475 // Test with correct buffer 476 test_EnumBuffer(Entries[i].Signature, &Buffer, sizeof(Buffer), &TableCount[i], &FirstTableID[i], 477 Entries[i].ErrInsuff, Entries[i].ErrSuccess); 478 } 479 480 // Test GetSystemFirmwareTable 481 for (i = 0; i < _countof(Entries); i++) 482 { 483 // Test with fake ID and NULL buffer 484 test_GetBuffer(Entries[i].Signature, 0xbeeffeed, NULL, sizeof(Buffer), 485 TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 486 // Test with fake ID and wrong buffer 487 test_GetBuffer(Entries[i].Signature, 0xbeeffeed, (PVOID *)(LONG_PTR)0xbeeffeed, sizeof(Buffer), 488 TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 489 // Test with fake ID and correct buffer 490 test_GetBuffer(Entries[i].Signature, 0xbeeffeed, &Buffer, sizeof(Buffer), 491 TRUE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 492 if (TableCount[i] == 0) 493 { 494 if (i < _countof(Entries) - 1) 495 { 496 ZeroMemory(&Sign, sizeof(Sign)); 497 *(DWORD *)&Sign = _byteswap_ulong(Entries[i].Signature); 498 skip("No tables for %s found. Skipping\n", 499 Sign); 500 } 501 continue; 502 } 503 // Test with correct ID and NULL buffer 504 test_GetBuffer(Entries[i].Signature, FirstTableID[i], NULL, sizeof(Buffer), 505 FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 506 // Test with correct ID and wrong buffer 507 test_GetBuffer(Entries[i].Signature, FirstTableID[i], (PVOID *)(LONG_PTR)0xbeeffeed, sizeof(Buffer), 508 FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 509 // Test with correct ID and correct buffer 510 test_GetBuffer(Entries[i].Signature, FirstTableID[i], &Buffer, sizeof(Buffer), 511 FALSE, Entries[i].ErrInsuff, Entries[i].ErrSuccess); 512 } 513 } 514 515 START_TEST(SystemFirmware) 516 { 517 HANDLE hKernel; 518 519 hKernel = GetModuleHandleW(L"kernel32.dll"); 520 if (!hKernel) 521 { 522 skip("kernel32.dll module not found. Can't proceed\n"); 523 return; 524 } 525 526 pEnumSystemFirmwareTables = (void *)fEnumSystemFirmwareTables; 527 pGetSystemFirmwareTable = (void *)fGetSystemFirmwareTable; 528 529 test_Functions(); 530 531 pEnumSystemFirmwareTables = (void *)GetProcAddress(hKernel, "EnumSystemFirmwareTables"); 532 pGetSystemFirmwareTable = (void *)GetProcAddress(hKernel, "GetSystemFirmwareTable"); 533 534 if (!pEnumSystemFirmwareTables) 535 { 536 skip("EnumSystemFirmwareTables not found. Can't proceed\n"); 537 return; 538 } 539 if (!pGetSystemFirmwareTable) 540 { 541 skip("GetSystemFirmwareTable not found. Can't proceed\n"); 542 return; 543 } 544 test_Functions(); 545 } 546