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