Reactos
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
25VOID
26WINAPI
27GetSystemInfoInternal(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
79static
80UINT
81BaseQuerySystemFirmware(
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 */
131SIZE_T
132WINAPI
133GetLargePageMinimum(VOID)
134{
135 return SharedUserData->LargePageMinimum;
136}
137
138/*
139 * @implemented
140 */
141VOID
142WINAPI
143GetSystemInfo(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 */
167BOOL
168WINAPI
169IsProcessorFeaturePresent(IN DWORD ProcessorFeature)
170{
171 if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return FALSE;
172 return ((BOOL)SharedUserData->ProcessorFeatures[ProcessorFeature]);
173}
174
175/*
176 * @implemented
177 */
178BOOL
179WINAPI
180GetSystemRegistryQuota(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 */
205VOID
206WINAPI
207GetNativeSystemInfo(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 */
231BOOL
232WINAPI
233GetLogicalProcessorInformation(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 */
263BOOL
264WINAPI
265GetNumaHighestNodeNumber(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 */
296BOOL
297WINAPI
298GetNumaNodeProcessorMask(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 */
331BOOL
332WINAPI
333GetNumaProcessorNode(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 */
385BOOL
386WINAPI
387GetNumaAvailableMemoryNode(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)
418DWORD
419WINAPI
420GetFirmwareEnvironmentVariableExW(
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_Success_(return > 0)
428DWORD
429WINAPI
430GetFirmwareEnvironmentVariableExA(
431 _In_ LPCSTR lpName,
432 _In_ LPCSTR lpGuid,
433 _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
434 _In_ DWORD nSize,
435 _Out_opt_ PDWORD pdwAttribubutes);
436
437BOOL
438WINAPI
439SetFirmwareEnvironmentVariableExW(
440 _In_ LPCWSTR lpName,
441 _In_ LPCWSTR lpGuid,
442 _In_reads_bytes_opt_(nSize) PVOID pValue,
443 _In_ DWORD nSize,
444 _In_ DWORD dwAttributes);
445
446BOOL
447WINAPI
448SetFirmwareEnvironmentVariableExA(
449 _In_ LPCSTR lpName,
450 _In_ LPCSTR lpGuid,
451 _In_reads_bytes_opt_(nSize) PVOID pValue,
452 _In_ DWORD nSize,
453 _In_ DWORD dwAttributes);
454
455_Success_(return > 0)
456DWORD
457WINAPI
458GetFirmwareEnvironmentVariableW(
459 _In_ LPCWSTR lpName,
460 _In_ LPCWSTR lpGuid,
461 _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer,
462 _In_ DWORD nSize)
463{
464 return GetFirmwareEnvironmentVariableExW(lpName, lpGuid, pBuffer, nSize, NULL);
465}
466
467BOOL
468WINAPI
469SetFirmwareEnvironmentVariableW(
470 _In_ LPCWSTR lpName,
471 _In_ LPCWSTR lpGuid,
472 _In_reads_bytes_opt_(nSize) PVOID pValue,
473 _In_ DWORD nSize)
474{
475 return SetFirmwareEnvironmentVariableExW(lpName,
476 lpGuid,
477 pValue,
478 nSize,
479 VARIABLE_ATTRIBUTE_NON_VOLATILE);
480}
481
482/**
483 * @name EnumSystemFirmwareTables
484 * @implemented
485 *
486 * Obtains firmware table identifiers.
487 * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-enumsystemfirmwaretables
488 *
489 * @param FirmwareTableProviderSignature
490 * Can be either ACPI, FIRM, or RSMB.
491 *
492 * @param pFirmwareTableBuffer
493 * Pointer to the output buffer, can be NULL.
494 *
495 * @param BufferSize
496 * Size of the output buffer.
497 *
498 * @return
499 * Actual size of the data in case of success, 0 otherwise.
500 *
501 * @remarks
502 * Data would be written to buffer only if the specified size is
503 * larger or equal to the actual size, in the other case Last Error
504 * value would be set to ERROR_INSUFFICIENT_BUFFER.
505 * In case of incorrect provider signature, Last Error value would be
506 * set to ERROR_INVALID_FUNCTION.
507 *
508 */
509UINT
510WINAPI
511EnumSystemFirmwareTables(
512 _In_ DWORD FirmwareTableProviderSignature,
513 _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableEnumBuffer,
514 _In_ DWORD BufferSize)
515{
516 return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
517 0,
518 pFirmwareTableEnumBuffer,
519 BufferSize,
520 SystemFirmwareTable_Enumerate);
521}
522
523/**
524 * @name GetSystemFirmwareTable
525 * @implemented
526 *
527 * Obtains the firmware table data.
528 * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable
529 *
530 * @param FirmwareTableProviderSignature
531 * Can be either ACPI, FIRM, or RSMB.
532 *
533 * @param FirmwareTableID
534 * Correct table identifier.
535 *
536 * @param pFirmwareTableBuffer
537 * Pointer to the output buffer, can be NULL.
538 *
539 * @param BufferSize
540 * Size of the output buffer.
541 *
542 * @return
543 * Actual size of the data in case of success, 0 otherwise.
544 *
545 * @remarks
546 * Data would be written to buffer only if the specified size is
547 * larger or equal to the actual size, in the other case Last Error
548 * value would be set to ERROR_INSUFFICIENT_BUFFER.
549 * In case of incorrect provider signature, Last Error value would be
550 * set to ERROR_INVALID_FUNCTION.
551 * Also Last Error value becomes ERROR_NOT_FOUND if incorrect
552 * table identifier was specified along with ACPI provider, and
553 * ERROR_INVALID_PARAMETER along with FIRM provider. The RSMB provider
554 * accepts any table identifier.
555 *
556 */
557UINT
558WINAPI
559GetSystemFirmwareTable(
560 _In_ DWORD FirmwareTableProviderSignature,
561 _In_ DWORD FirmwareTableID,
562 _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
563 _In_ DWORD BufferSize)
564{
565 return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
566 FirmwareTableID,
567 pFirmwareTableBuffer,
568 BufferSize,
569 SystemFirmwareTable_Get);
570}
571
572/*
573 * @unimplemented
574 */
575BOOL
576WINAPI
577GetSystemFileCacheSize(OUT PSIZE_T lpMinimumFileCacheSize,
578 OUT PSIZE_T lpMaximumFileCacheSize,
579 OUT PDWORD lpFlags)
580{
581 STUB;
582 return FALSE;
583}
584
585/*
586 * @unimplemented
587 */
588BOOL
589WINAPI
590SetSystemFileCacheSize(IN SIZE_T MinimumFileCacheSize,
591 IN SIZE_T MaximumFileCacheSize,
592 IN DWORD Flags)
593{
594 STUB;
595 return FALSE;
596}
597
598/*
599 * @unimplemented
600 */
601LONG
602WINAPI
603GetCurrentPackageId(UINT32 *BufferLength,
604 BYTE *Buffer)
605{
606 STUB;
607 return APPMODEL_ERROR_NO_PACKAGE;
608}