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