xref: /reactos/dll/win32/kernel32/client/sysinfo.c (revision 048ea61a)
1 /*
2  * PROJECT:         ReactOS Win32 Base API
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         System Information Functions
5  * COPYRIGHT:       Emanuele Aliberti
6  *                  Christoph von Wittich
7  *                  Thomas Weidenmueller
8  *                  Gunnar Andre Dalsnes
9  *                  Stanislav Motylkov (x86corez@gmail.com)
10  *                  Mark Jansen (mark.jansen@reactos.org)
11  *                  Copyright 2023 Ratin Gao <ratin@knsoft.org>
12  */
13 
14 /* INCLUDES *******************************************************************/
15 
16 #include <k32.h>
17 
18 #define NDEBUG
19 #include <debug.h>
20 
21 #define PV_NT351 0x00030033
22 
23 /* PRIVATE FUNCTIONS **********************************************************/
24 
25 VOID
26 WINAPI
27 GetSystemInfoInternal(IN PSYSTEM_BASIC_INFORMATION BasicInfo,
28                       IN PSYSTEM_PROCESSOR_INFORMATION ProcInfo,
29                       OUT LPSYSTEM_INFO SystemInfo)
30 {
31     RtlZeroMemory(SystemInfo, sizeof (SYSTEM_INFO));
32     SystemInfo->wProcessorArchitecture = ProcInfo->ProcessorArchitecture;
33     SystemInfo->wReserved = 0;
34     SystemInfo->dwPageSize = BasicInfo->PageSize;
35     SystemInfo->lpMinimumApplicationAddress = (PVOID)BasicInfo->MinimumUserModeAddress;
36     SystemInfo->lpMaximumApplicationAddress = (PVOID)BasicInfo->MaximumUserModeAddress;
37     SystemInfo->dwActiveProcessorMask = BasicInfo->ActiveProcessorsAffinityMask;
38     SystemInfo->dwNumberOfProcessors = BasicInfo->NumberOfProcessors;
39     SystemInfo->wProcessorLevel = ProcInfo->ProcessorLevel;
40     SystemInfo->wProcessorRevision = ProcInfo->ProcessorRevision;
41     SystemInfo->dwAllocationGranularity = BasicInfo->AllocationGranularity;
42 
43     switch (ProcInfo->ProcessorArchitecture)
44     {
45         case PROCESSOR_ARCHITECTURE_INTEL:
46             switch (ProcInfo->ProcessorLevel)
47             {
48                 case 3:
49                     SystemInfo->dwProcessorType = PROCESSOR_INTEL_386;
50                     break;
51                 case 4:
52                     SystemInfo->dwProcessorType = PROCESSOR_INTEL_486;
53                     break;
54                 default:
55                     SystemInfo->dwProcessorType = PROCESSOR_INTEL_PENTIUM;
56             }
57             break;
58 
59         case PROCESSOR_ARCHITECTURE_AMD64:
60             SystemInfo->dwProcessorType = PROCESSOR_AMD_X8664;
61             break;
62 
63         case PROCESSOR_ARCHITECTURE_IA64:
64             SystemInfo->dwProcessorType = PROCESSOR_INTEL_IA64;
65             break;
66 
67         default:
68             SystemInfo->dwProcessorType = 0;
69             break;
70     }
71 
72     if (PV_NT351 > GetProcessVersion(0))
73     {
74         SystemInfo->wProcessorLevel = 0;
75         SystemInfo->wProcessorRevision = 0;
76     }
77 }
78 
79 static
80 UINT
81 BaseQuerySystemFirmware(
82     _In_ DWORD FirmwareTableProviderSignature,
83     _In_ DWORD FirmwareTableID,
84     _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
85     _In_ DWORD BufferSize,
86     _In_ SYSTEM_FIRMWARE_TABLE_ACTION Action)
87 {
88     SYSTEM_FIRMWARE_TABLE_INFORMATION* SysFirmwareInfo;
89     ULONG Result = 0, ReturnedSize;
90     ULONG TotalSize = BufferSize + sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION);
91     NTSTATUS Status;
92 
93     SysFirmwareInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TotalSize);
94     if (!SysFirmwareInfo)
95     {
96         SetLastError(ERROR_INVALID_PARAMETER);
97         return 0;
98     }
99     _SEH2_TRY
100     {
101         SysFirmwareInfo->ProviderSignature = FirmwareTableProviderSignature;
102         SysFirmwareInfo->TableID = FirmwareTableID;
103         SysFirmwareInfo->Action = Action;
104         SysFirmwareInfo->TableBufferLength = BufferSize;
105 
106         Status = NtQuerySystemInformation(SystemFirmwareTableInformation, SysFirmwareInfo, TotalSize, &ReturnedSize);
107 
108         if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
109             Result = SysFirmwareInfo->TableBufferLength;
110 
111         if (NT_SUCCESS(Status) && pFirmwareTableBuffer)
112         {
113             RtlCopyMemory(pFirmwareTableBuffer, SysFirmwareInfo->TableBuffer, SysFirmwareInfo->TableBufferLength);
114         }
115     }
116     _SEH2_FINALLY
117     {
118         RtlFreeHeap(RtlGetProcessHeap(), 0, SysFirmwareInfo);
119     }
120     _SEH2_END;
121 
122     BaseSetLastNTError(Status);
123     return Result;
124 }
125 
126 /* PUBLIC FUNCTIONS ***********************************************************/
127 
128 /*
129  * @implemented
130  */
131 SIZE_T
132 WINAPI
133 GetLargePageMinimum(VOID)
134 {
135     return SharedUserData->LargePageMinimum;
136 }
137 
138 /*
139  * @implemented
140  */
141 VOID
142 WINAPI
143 GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
144 {
145     SYSTEM_BASIC_INFORMATION BasicInfo;
146     SYSTEM_PROCESSOR_INFORMATION ProcInfo;
147     NTSTATUS Status;
148 
149     Status = NtQuerySystemInformation(SystemBasicInformation,
150                                       &BasicInfo,
151                                       sizeof(BasicInfo),
152                                       0);
153     if (!NT_SUCCESS(Status)) return;
154 
155     Status = NtQuerySystemInformation(SystemProcessorInformation,
156                                       &ProcInfo,
157                                       sizeof(ProcInfo),
158                                       0);
159     if (!NT_SUCCESS(Status)) return;
160 
161     GetSystemInfoInternal(&BasicInfo, &ProcInfo, lpSystemInfo);
162 }
163 
164 /*
165  * @implemented
166  */
167 BOOL
168 WINAPI
169 IsProcessorFeaturePresent(IN DWORD ProcessorFeature)
170 {
171     if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return FALSE;
172     return ((BOOL)SharedUserData->ProcessorFeatures[ProcessorFeature]);
173 }
174 
175 /*
176  * @implemented
177  */
178 BOOL
179 WINAPI
180 GetSystemRegistryQuota(OUT PDWORD pdwQuotaAllowed,
181                        OUT PDWORD pdwQuotaUsed)
182 {
183     SYSTEM_REGISTRY_QUOTA_INFORMATION QuotaInfo;
184     ULONG BytesWritten;
185     NTSTATUS Status;
186 
187     Status = NtQuerySystemInformation(SystemRegistryQuotaInformation,
188                                       &QuotaInfo,
189                                       sizeof(QuotaInfo),
190                                       &BytesWritten);
191     if (NT_SUCCESS(Status))
192     {
193       if (pdwQuotaAllowed) *pdwQuotaAllowed = QuotaInfo.RegistryQuotaAllowed;
194       if (pdwQuotaUsed) *pdwQuotaUsed = QuotaInfo.RegistryQuotaUsed;
195       return TRUE;
196     }
197 
198     BaseSetLastNTError(Status);
199     return FALSE;
200 }
201 
202 /*
203  * @implemented
204  */
205 VOID
206 WINAPI
207 GetNativeSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
208 {
209     SYSTEM_BASIC_INFORMATION BasicInfo;
210     SYSTEM_PROCESSOR_INFORMATION ProcInfo;
211     NTSTATUS Status;
212 
213     Status = RtlGetNativeSystemInformation(SystemBasicInformation,
214                                            &BasicInfo,
215                                            sizeof(BasicInfo),
216                                            0);
217     if (!NT_SUCCESS(Status)) return;
218 
219     Status = RtlGetNativeSystemInformation(SystemProcessorInformation,
220                                            &ProcInfo,
221                                            sizeof(ProcInfo),
222                                            0);
223     if (!NT_SUCCESS(Status)) return;
224 
225     GetSystemInfoInternal(&BasicInfo, &ProcInfo, lpSystemInfo);
226 }
227 
228 /*
229  * @implemented
230  */
231 BOOL
232 WINAPI
233 GetLogicalProcessorInformation(OUT PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,
234                                IN OUT PDWORD ReturnLength)
235 {
236     NTSTATUS Status;
237 
238     if (!ReturnLength)
239     {
240         SetLastError(ERROR_INVALID_PARAMETER);
241         return FALSE;
242     }
243 
244     Status = NtQuerySystemInformation(SystemLogicalProcessorInformation,
245                                       Buffer,
246                                       *ReturnLength,
247                                       ReturnLength);
248 
249     /* Normalize the error to what Win32 expects */
250     if (Status == STATUS_INFO_LENGTH_MISMATCH) Status = STATUS_BUFFER_TOO_SMALL;
251     if (!NT_SUCCESS(Status))
252     {
253         BaseSetLastNTError(Status);
254         return FALSE;
255     }
256 
257     return TRUE;
258 }
259 
260 /*
261  * @implemented
262  */
263 BOOL
264 WINAPI
265 GetNumaHighestNodeNumber(OUT PULONG HighestNodeNumber)
266 {
267     NTSTATUS Status;
268     ULONG Length;
269     ULONG PartialInfo[2]; // First two members of SYSTEM_NUMA_INFORMATION
270 
271     /* Query partial NUMA info */
272     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
273                                       PartialInfo,
274                                       sizeof(PartialInfo),
275                                       &Length);
276     if (!NT_SUCCESS(Status))
277     {
278         BaseSetLastNTError(Status);
279         return FALSE;
280     }
281 
282     if (Length < sizeof(ULONG))
283     {
284         SetLastError(ERROR_INVALID_PARAMETER);
285         return FALSE;
286     }
287 
288     /* First member of the struct is the highest node number */
289     *HighestNodeNumber = PartialInfo[0];
290     return TRUE;
291 }
292 
293 /*
294  * @implemented
295  */
296 BOOL
297 WINAPI
298 GetNumaNodeProcessorMask(IN UCHAR Node,
299                          OUT PULONGLONG ProcessorMask)
300 {
301     NTSTATUS Status;
302     SYSTEM_NUMA_INFORMATION NumaInformation;
303     ULONG Length;
304 
305     /* Query NUMA information */
306     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
307                                       &NumaInformation,
308                                       sizeof(NumaInformation),
309                                       &Length);
310     if (!NT_SUCCESS(Status))
311     {
312         BaseSetLastNTError(Status);
313         return FALSE;
314     }
315 
316     /* Validate input node number */
317     if (Node > NumaInformation.HighestNodeNumber)
318     {
319         SetLastError(ERROR_INVALID_PARAMETER);
320         return FALSE;
321     }
322 
323     /* Return mask for that node */
324     *ProcessorMask = NumaInformation.ActiveProcessorsAffinityMask[Node];
325     return TRUE;
326 }
327 
328 /*
329  * @implemented
330  */
331 BOOL
332 WINAPI
333 GetNumaProcessorNode(IN UCHAR Processor,
334                      OUT PUCHAR NodeNumber)
335 {
336     NTSTATUS Status;
337     SYSTEM_NUMA_INFORMATION NumaInformation;
338     ULONG Length;
339     ULONG Node;
340     ULONGLONG Proc;
341 
342     /* Can't handle processor number >= 32 */
343     if (Processor >= MAXIMUM_PROCESSORS)
344     {
345         *NodeNumber = -1;
346         SetLastError(ERROR_INVALID_PARAMETER);
347         return FALSE;
348     }
349 
350     /* Query NUMA information */
351     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
352                                       &NumaInformation,
353                                       sizeof(NumaInformation),
354                                       &Length);
355     if (!NT_SUCCESS(Status))
356     {
357         *NodeNumber = -1;
358         BaseSetLastNTError(Status);
359         return FALSE;
360     }
361 
362     /* Find ourselves */
363     Node = 0;
364     Proc = 1ULL << Processor;
365     while ((Proc & NumaInformation.ActiveProcessorsAffinityMask[Node]) == 0ULL)
366     {
367         ++Node;
368         /* Out of options */
369         if (Node > NumaInformation.HighestNodeNumber)
370         {
371             *NodeNumber = -1;
372             SetLastError(ERROR_INVALID_PARAMETER);
373             return FALSE;
374         }
375     }
376 
377     /* Return found node */
378     *NodeNumber = Node;
379     return TRUE;
380 }
381 
382 /*
383  * @implemented
384  */
385 BOOL
386 WINAPI
387 GetNumaAvailableMemoryNode(IN UCHAR Node,
388                            OUT PULONGLONG AvailableBytes)
389 {
390     NTSTATUS Status;
391     SYSTEM_NUMA_INFORMATION NumaInformation;
392     ULONG Length;
393 
394     /* Query NUMA information */
395     Status = NtQuerySystemInformation(SystemNumaAvailableMemory,
396                                       &NumaInformation,
397                                       sizeof(NumaInformation),
398                                       &Length);
399     if (!NT_SUCCESS(Status))
400     {
401         BaseSetLastNTError(Status);
402         return FALSE;
403     }
404 
405     /* Validate input node number */
406     if (Node > NumaInformation.HighestNodeNumber)
407     {
408         SetLastError(ERROR_INVALID_PARAMETER);
409         return FALSE;
410     }
411 
412     /* Return available memory for that node */
413     *AvailableBytes = NumaInformation.AvailableMemory[Node];
414     return TRUE;
415 }
416 
417 _Success_(return > 0)
418 DWORD
419 WINAPI
420 GetFirmwareEnvironmentVariableExW(
421     _In_ LPCWSTR lpName,
422     _In_ LPCWSTR lpGuid,
423     _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
424     _In_ DWORD nSize,
425     _Out_opt_ PDWORD pdwAttribubutes)
426 {
427     NTSTATUS Status;
428     UNICODE_STRING VariableName, Namespace;
429     GUID VendorGuid;
430     ULONG Length;
431 
432     /* Check input parameters and build NT strings */
433     if (!lpName || !lpGuid)
434     {
435         SetLastError(ERROR_INVALID_PARAMETER);
436         return 0;
437     }
438     RtlInitUnicodeString(&VariableName, lpName);
439     RtlInitUnicodeString(&Namespace, lpGuid);
440     Status = RtlGUIDFromString(&Namespace, &VendorGuid);
441     if (!NT_SUCCESS(Status))
442     {
443         BaseSetLastNTError(Status);
444         return 0;
445     }
446 
447     /* Query firmware system environment variable value */
448     Length = nSize;
449     Status = NtQuerySystemEnvironmentValueEx(&VariableName,
450                                              &VendorGuid,
451                                              pBuffer,
452                                              &Length,
453                                              pdwAttribubutes);
454     if (!NT_SUCCESS(Status))
455     {
456         BaseSetLastNTError(Status);
457         return 0;
458     }
459 
460     return Length;
461 }
462 
463 _Success_(return > 0)
464 DWORD
465 WINAPI
466 GetFirmwareEnvironmentVariableExA(
467     _In_ LPCSTR lpName,
468     _In_ LPCSTR lpGuid,
469     _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
470     _In_ DWORD nSize,
471     _Out_opt_ PDWORD pdwAttribubutes)
472 {
473     NTSTATUS Status;
474     DWORD Length;
475     UNICODE_STRING VariableName, Namespace;
476     ANSI_STRING AnsiVariableName, AnsiNamespace;
477 
478     /* Check input parameters and build NT strings */
479     if (!lpName || !lpGuid)
480     {
481         SetLastError(ERROR_INVALID_PARAMETER);
482         return 0;
483     }
484     RtlInitString(&AnsiVariableName, lpName);
485     Status = RtlAnsiStringToUnicodeString(&VariableName, &AnsiVariableName, TRUE);
486     if (!NT_SUCCESS(Status))
487     {
488         BaseSetLastNTError(Status);
489         return 0;
490     }
491     RtlInitString(&AnsiNamespace, lpGuid);
492     Status = RtlAnsiStringToUnicodeString(&Namespace, &AnsiNamespace, TRUE);
493     if (!NT_SUCCESS(Status))
494     {
495         RtlFreeUnicodeString(&VariableName);
496         BaseSetLastNTError(Status);
497         return 0;
498     }
499 
500     /* Call unicode version interface */
501     Length = GetFirmwareEnvironmentVariableExW(VariableName.Buffer,
502                                                Namespace.Buffer,
503                                                pBuffer,
504                                                nSize,
505                                                pdwAttribubutes);
506 
507     /* Cleanup and return */
508     RtlFreeUnicodeString(&Namespace);
509     RtlFreeUnicodeString(&VariableName);
510     return Length;
511 }
512 
513 _Success_(return > 0)
514 DWORD
515 WINAPI
516 GetFirmwareEnvironmentVariableW(
517     _In_ LPCWSTR lpName,
518     _In_ LPCWSTR lpGuid,
519     _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
520     _In_ DWORD nSize)
521 {
522     return GetFirmwareEnvironmentVariableExW(lpName, lpGuid, pBuffer, nSize, NULL);
523 }
524 
525 _Success_(return > 0)
526 DWORD
527 WINAPI
528 GetFirmwareEnvironmentVariableA(
529     _In_ LPCSTR lpName,
530     _In_ LPCSTR lpGuid,
531     _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
532     _In_ DWORD nSize)
533 {
534     return GetFirmwareEnvironmentVariableExA(lpName, lpGuid, pBuffer, nSize, NULL);
535 }
536 
537 BOOL
538 WINAPI
539 SetFirmwareEnvironmentVariableExW(
540     _In_ LPCWSTR lpName,
541     _In_ LPCWSTR lpGuid,
542     _In_reads_bytes_opt_(nSize) PVOID pValue,
543     _In_ DWORD nSize,
544     _In_ DWORD dwAttributes)
545 {
546     NTSTATUS Status;
547     UNICODE_STRING VariableName, Namespace;
548     GUID VendorGuid;
549 
550     /* Check input parameters and build NT strings */
551     if (!lpName || !lpGuid)
552     {
553         SetLastError(ERROR_INVALID_PARAMETER);
554         return FALSE;
555     }
556     RtlInitUnicodeString(&VariableName, lpName);
557     RtlInitUnicodeString(&Namespace, lpGuid);
558     Status = RtlGUIDFromString(&Namespace, &VendorGuid);
559     if (!NT_SUCCESS(Status))
560     {
561         BaseSetLastNTError(Status);
562         return FALSE;
563     }
564 
565     /* Set firmware system environment variable value */
566     Status = NtSetSystemEnvironmentValueEx(&VariableName,
567                                            &VendorGuid,
568                                            pValue,
569                                            nSize,
570                                            dwAttributes);
571     if (!NT_SUCCESS(Status))
572     {
573         BaseSetLastNTError(Status);
574         return FALSE;
575     }
576 
577     return TRUE;
578 }
579 
580 BOOL
581 WINAPI
582 SetFirmwareEnvironmentVariableExA(
583     _In_ LPCSTR lpName,
584     _In_ LPCSTR lpGuid,
585     _In_reads_bytes_opt_(nSize) PVOID pValue,
586     _In_ DWORD nSize,
587     _In_ DWORD dwAttributes)
588 {
589     NTSTATUS Status;
590     BOOL Result;
591     UNICODE_STRING VariableName, Namespace;
592     ANSI_STRING AnsiVariableName, AnsiNamespace;
593 
594     /* Check input parameters and build NT strings */
595     if (!lpName || !lpGuid)
596     {
597         SetLastError(ERROR_INVALID_PARAMETER);
598         return FALSE;
599     }
600     RtlInitString(&AnsiVariableName, lpName);
601     Status = RtlAnsiStringToUnicodeString(&VariableName, &AnsiVariableName, TRUE);
602     if (!NT_SUCCESS(Status))
603     {
604         BaseSetLastNTError(Status);
605         return FALSE;
606     }
607     RtlInitString(&AnsiNamespace, lpGuid);
608     Status = RtlAnsiStringToUnicodeString(&Namespace, &AnsiNamespace, TRUE);
609     if (!NT_SUCCESS(Status))
610     {
611         RtlFreeUnicodeString(&VariableName);
612         BaseSetLastNTError(Status);
613         return FALSE;
614     }
615 
616     /* Call unicode version interface */
617     Result = SetFirmwareEnvironmentVariableExW(VariableName.Buffer,
618                                                Namespace.Buffer,
619                                                pValue,
620                                                nSize,
621                                                dwAttributes);
622 
623     /* Cleanup and return */
624     RtlFreeUnicodeString(&Namespace);
625     RtlFreeUnicodeString(&VariableName);
626     return Result;
627 }
628 
629 BOOL
630 WINAPI
631 SetFirmwareEnvironmentVariableW(
632     _In_ LPCWSTR lpName,
633     _In_ LPCWSTR lpGuid,
634     _In_reads_bytes_opt_(nSize) PVOID pValue,
635     _In_ DWORD nSize)
636 {
637     return SetFirmwareEnvironmentVariableExW(lpName,
638                                              lpGuid,
639                                              pValue,
640                                              nSize,
641                                              VARIABLE_ATTRIBUTE_NON_VOLATILE);
642 }
643 
644 BOOL
645 WINAPI
646 SetFirmwareEnvironmentVariableA(
647     _In_ LPCSTR lpName,
648     _In_ LPCSTR lpGuid,
649     _In_reads_bytes_opt_(nSize) PVOID pValue,
650     _In_ DWORD nSize)
651 {
652     return SetFirmwareEnvironmentVariableExA(lpName,
653                                              lpGuid,
654                                              pValue,
655                                              nSize,
656                                              VARIABLE_ATTRIBUTE_NON_VOLATILE);
657 }
658 
659 /**
660  * @name EnumSystemFirmwareTables
661  * @implemented
662  *
663  * Obtains firmware table identifiers.
664  * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-enumsystemfirmwaretables
665  *
666  * @param FirmwareTableProviderSignature
667  * Can be either ACPI, FIRM, or RSMB.
668  *
669  * @param pFirmwareTableBuffer
670  * Pointer to the output buffer, can be NULL.
671  *
672  * @param BufferSize
673  * Size of the output buffer.
674  *
675  * @return
676  * Actual size of the data in case of success, 0 otherwise.
677  *
678  * @remarks
679  * Data would be written to buffer only if the specified size is
680  * larger or equal to the actual size, in the other case Last Error
681  * value would be set to ERROR_INSUFFICIENT_BUFFER.
682  * In case of incorrect provider signature, Last Error value would be
683  * set to ERROR_INVALID_FUNCTION.
684  *
685  */
686 UINT
687 WINAPI
688 EnumSystemFirmwareTables(
689     _In_ DWORD FirmwareTableProviderSignature,
690     _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableEnumBuffer,
691     _In_ DWORD BufferSize)
692 {
693     return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
694                                    0,
695                                    pFirmwareTableEnumBuffer,
696                                    BufferSize,
697                                    SystemFirmwareTable_Enumerate);
698 }
699 
700 /**
701  * @name GetSystemFirmwareTable
702  * @implemented
703  *
704  * Obtains the firmware table data.
705  * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable
706  *
707  * @param FirmwareTableProviderSignature
708  * Can be either ACPI, FIRM, or RSMB.
709  *
710  * @param FirmwareTableID
711  * Correct table identifier.
712  *
713  * @param pFirmwareTableBuffer
714  * Pointer to the output buffer, can be NULL.
715  *
716  * @param BufferSize
717  * Size of the output buffer.
718  *
719  * @return
720  * Actual size of the data in case of success, 0 otherwise.
721  *
722  * @remarks
723  * Data would be written to buffer only if the specified size is
724  * larger or equal to the actual size, in the other case Last Error
725  * value would be set to ERROR_INSUFFICIENT_BUFFER.
726  * In case of incorrect provider signature, Last Error value would be
727  * set to ERROR_INVALID_FUNCTION.
728  * Also Last Error value becomes ERROR_NOT_FOUND if incorrect
729  * table identifier was specified along with ACPI provider, and
730  * ERROR_INVALID_PARAMETER along with FIRM provider. The RSMB provider
731  * accepts any table identifier.
732  *
733  */
734 UINT
735 WINAPI
736 GetSystemFirmwareTable(
737     _In_ DWORD FirmwareTableProviderSignature,
738     _In_ DWORD FirmwareTableID,
739     _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
740     _In_ DWORD BufferSize)
741 {
742     return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
743                                    FirmwareTableID,
744                                    pFirmwareTableBuffer,
745                                    BufferSize,
746                                    SystemFirmwareTable_Get);
747 }
748 
749 /*
750  * @unimplemented
751  */
752 BOOL
753 WINAPI
754 GetSystemFileCacheSize(OUT PSIZE_T lpMinimumFileCacheSize,
755                        OUT PSIZE_T lpMaximumFileCacheSize,
756                        OUT PDWORD lpFlags)
757 {
758     STUB;
759     return FALSE;
760 }
761 
762 /*
763  * @unimplemented
764  */
765 BOOL
766 WINAPI
767 SetSystemFileCacheSize(IN SIZE_T MinimumFileCacheSize,
768                        IN SIZE_T MaximumFileCacheSize,
769                        IN DWORD Flags)
770 {
771     STUB;
772     return FALSE;
773 }
774 
775 /*
776  * @unimplemented
777  */
778 LONG
779 WINAPI
780 GetCurrentPackageId(UINT32 *BufferLength,
781                     BYTE *Buffer)
782 {
783     STUB;
784     return APPMODEL_ERROR_NO_PACKAGE;
785 }
786