xref: /reactos/dll/win32/kernel32/client/sysinfo.c (revision 62919904)
1 /*
2  * PROJECT:         ReactOS Win32 Base API
3  * LICENSE:         See COPYING in the top level directory
4  * FILE:            dll/win32/kernel32/client/sysinfo.c
5  * PURPOSE:         System Information Functions
6  * PROGRAMMERS:     Emanuele Aliberti
7  *                  Christoph von Wittich
8  *                  Thomas Weidenmueller
9  *                  Gunnar Andre Dalsnes
10  *                  Stanislav Motylkov (x86corez@gmail.com)
11  *                  Mark Jansen (mark.jansen@reactos.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(IN DWORD FirmwareTableProviderSignature,
82                         IN DWORD FirmwareTableID,
83                         OUT PVOID pFirmwareTableBuffer,
84                         IN DWORD BufferSize,
85                         IN SYSTEM_FIRMWARE_TABLE_ACTION Action)
86 {
87     SYSTEM_FIRMWARE_TABLE_INFORMATION* SysFirmwareInfo;
88     ULONG Result = 0, ReturnedSize;
89     ULONG TotalSize = BufferSize + sizeof(SYSTEM_FIRMWARE_TABLE_INFORMATION);
90     NTSTATUS Status;
91 
92     SysFirmwareInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TotalSize);
93     if (!SysFirmwareInfo)
94     {
95         SetLastError(ERROR_INVALID_PARAMETER);
96         return 0;
97     }
98     _SEH2_TRY
99     {
100         SysFirmwareInfo->ProviderSignature = FirmwareTableProviderSignature;
101         SysFirmwareInfo->TableID = FirmwareTableID;
102         SysFirmwareInfo->Action = Action;
103         SysFirmwareInfo->TableBufferLength = BufferSize;
104 
105         Status = NtQuerySystemInformation(SystemFirmwareTableInformation, SysFirmwareInfo, TotalSize, &ReturnedSize);
106 
107         if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
108             Result = SysFirmwareInfo->TableBufferLength;
109 
110         if (NT_SUCCESS(Status) && pFirmwareTableBuffer)
111         {
112             RtlCopyMemory(pFirmwareTableBuffer, SysFirmwareInfo->TableBuffer, SysFirmwareInfo->TableBufferLength);
113         }
114     }
115     _SEH2_FINALLY
116     {
117         RtlFreeHeap(RtlGetProcessHeap(), 0, SysFirmwareInfo);
118     }
119     _SEH2_END;
120 
121     BaseSetLastNTError(Status);
122     return Result;
123 }
124 
125 /* PUBLIC FUNCTIONS ***********************************************************/
126 
127 /*
128  * @implemented
129  */
130 SIZE_T
131 WINAPI
132 GetLargePageMinimum(VOID)
133 {
134     return SharedUserData->LargePageMinimum;
135 }
136 
137 /*
138  * @implemented
139  */
140 VOID
141 WINAPI
142 GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
143 {
144     SYSTEM_BASIC_INFORMATION BasicInfo;
145     SYSTEM_PROCESSOR_INFORMATION ProcInfo;
146     NTSTATUS Status;
147 
148     Status = NtQuerySystemInformation(SystemBasicInformation,
149                                       &BasicInfo,
150                                       sizeof(BasicInfo),
151                                       0);
152     if (!NT_SUCCESS(Status)) return;
153 
154     Status = NtQuerySystemInformation(SystemProcessorInformation,
155                                       &ProcInfo,
156                                       sizeof(ProcInfo),
157                                       0);
158     if (!NT_SUCCESS(Status)) return;
159 
160     GetSystemInfoInternal(&BasicInfo, &ProcInfo, lpSystemInfo);
161 }
162 
163 /*
164  * @implemented
165  */
166 BOOL
167 WINAPI
168 IsProcessorFeaturePresent(IN DWORD ProcessorFeature)
169 {
170     if (ProcessorFeature >= PROCESSOR_FEATURE_MAX) return FALSE;
171     return ((BOOL)SharedUserData->ProcessorFeatures[ProcessorFeature]);
172 }
173 
174 /*
175  * @implemented
176  */
177 BOOL
178 WINAPI
179 GetSystemRegistryQuota(OUT PDWORD pdwQuotaAllowed,
180                        OUT PDWORD pdwQuotaUsed)
181 {
182     SYSTEM_REGISTRY_QUOTA_INFORMATION QuotaInfo;
183     ULONG BytesWritten;
184     NTSTATUS Status;
185 
186     Status = NtQuerySystemInformation(SystemRegistryQuotaInformation,
187                                       &QuotaInfo,
188                                       sizeof(QuotaInfo),
189                                       &BytesWritten);
190     if (NT_SUCCESS(Status))
191     {
192       if (pdwQuotaAllowed) *pdwQuotaAllowed = QuotaInfo.RegistryQuotaAllowed;
193       if (pdwQuotaUsed) *pdwQuotaUsed = QuotaInfo.RegistryQuotaUsed;
194       return TRUE;
195     }
196 
197     BaseSetLastNTError(Status);
198     return FALSE;
199 }
200 
201 /*
202  * @implemented
203  */
204 VOID
205 WINAPI
206 GetNativeSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
207 {
208     SYSTEM_BASIC_INFORMATION BasicInfo;
209     SYSTEM_PROCESSOR_INFORMATION ProcInfo;
210     NTSTATUS Status;
211 
212     Status = RtlGetNativeSystemInformation(SystemBasicInformation,
213                                            &BasicInfo,
214                                            sizeof(BasicInfo),
215                                            0);
216     if (!NT_SUCCESS(Status)) return;
217 
218     Status = RtlGetNativeSystemInformation(SystemProcessorInformation,
219                                            &ProcInfo,
220                                            sizeof(ProcInfo),
221                                            0);
222     if (!NT_SUCCESS(Status)) return;
223 
224     GetSystemInfoInternal(&BasicInfo, &ProcInfo, lpSystemInfo);
225 }
226 
227 /*
228  * @implemented
229  */
230 BOOL
231 WINAPI
232 GetLogicalProcessorInformation(OUT PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,
233                                IN OUT PDWORD ReturnLength)
234 {
235     NTSTATUS Status;
236 
237     if (!ReturnLength)
238     {
239         SetLastError(ERROR_INVALID_PARAMETER);
240         return FALSE;
241     }
242 
243     Status = NtQuerySystemInformation(SystemLogicalProcessorInformation,
244                                       Buffer,
245                                       *ReturnLength,
246                                       ReturnLength);
247 
248     /* Normalize the error to what Win32 expects */
249     if (Status == STATUS_INFO_LENGTH_MISMATCH) Status = STATUS_BUFFER_TOO_SMALL;
250     if (!NT_SUCCESS(Status))
251     {
252         BaseSetLastNTError(Status);
253         return FALSE;
254     }
255 
256     return TRUE;
257 }
258 
259 /*
260  * @implemented
261  */
262 BOOL
263 WINAPI
264 GetNumaHighestNodeNumber(OUT PULONG HighestNodeNumber)
265 {
266     NTSTATUS Status;
267     ULONG Length;
268     ULONG PartialInfo[2]; // First two members of SYSTEM_NUMA_INFORMATION
269 
270     /* Query partial NUMA info */
271     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
272                                       PartialInfo,
273                                       sizeof(PartialInfo),
274                                       &Length);
275     if (!NT_SUCCESS(Status))
276     {
277         BaseSetLastNTError(Status);
278         return FALSE;
279     }
280 
281     if (Length < sizeof(ULONG))
282     {
283         SetLastError(ERROR_INVALID_PARAMETER);
284         return FALSE;
285     }
286 
287     /* First member of the struct is the highest node number */
288     *HighestNodeNumber = PartialInfo[0];
289     return TRUE;
290 }
291 
292 /*
293  * @implemented
294  */
295 BOOL
296 WINAPI
297 GetNumaNodeProcessorMask(IN UCHAR Node,
298                          OUT PULONGLONG ProcessorMask)
299 {
300     NTSTATUS Status;
301     SYSTEM_NUMA_INFORMATION NumaInformation;
302     ULONG Length;
303 
304     /* Query NUMA information */
305     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
306                                       &NumaInformation,
307                                       sizeof(NumaInformation),
308                                       &Length);
309     if (!NT_SUCCESS(Status))
310     {
311         BaseSetLastNTError(Status);
312         return FALSE;
313     }
314 
315     /* Validate input node number */
316     if (Node > NumaInformation.HighestNodeNumber)
317     {
318         SetLastError(ERROR_INVALID_PARAMETER);
319         return FALSE;
320     }
321 
322     /* Return mask for that node */
323     *ProcessorMask = NumaInformation.ActiveProcessorsAffinityMask[Node];
324     return TRUE;
325 }
326 
327 /*
328  * @implemented
329  */
330 BOOL
331 WINAPI
332 GetNumaProcessorNode(IN UCHAR Processor,
333                      OUT PUCHAR NodeNumber)
334 {
335     NTSTATUS Status;
336     SYSTEM_NUMA_INFORMATION NumaInformation;
337     ULONG Length;
338     ULONG Node;
339     ULONGLONG Proc;
340 
341     /* Can't handle processor number >= 32 */
342     if (Processor >= MAXIMUM_PROCESSORS)
343     {
344         *NodeNumber = -1;
345         SetLastError(ERROR_INVALID_PARAMETER);
346         return FALSE;
347     }
348 
349     /* Query NUMA information */
350     Status = NtQuerySystemInformation(SystemNumaProcessorMap,
351                                       &NumaInformation,
352                                       sizeof(NumaInformation),
353                                       &Length);
354     if (!NT_SUCCESS(Status))
355     {
356         *NodeNumber = -1;
357         BaseSetLastNTError(Status);
358         return FALSE;
359     }
360 
361     /* Find ourselves */
362     Node = 0;
363     Proc = 1ULL << Processor;
364     while ((Proc & NumaInformation.ActiveProcessorsAffinityMask[Node]) == 0ULL)
365     {
366         ++Node;
367         /* Out of options */
368         if (Node > NumaInformation.HighestNodeNumber)
369         {
370             *NodeNumber = -1;
371             SetLastError(ERROR_INVALID_PARAMETER);
372             return FALSE;
373         }
374     }
375 
376     /* Return found node */
377     *NodeNumber = Node;
378     return TRUE;
379 }
380 
381 /*
382  * @implemented
383  */
384 BOOL
385 WINAPI
386 GetNumaAvailableMemoryNode(IN UCHAR Node,
387                            OUT PULONGLONG AvailableBytes)
388 {
389     NTSTATUS Status;
390     SYSTEM_NUMA_INFORMATION NumaInformation;
391     ULONG Length;
392 
393     /* Query NUMA information */
394     Status = NtQuerySystemInformation(SystemNumaAvailableMemory,
395                                       &NumaInformation,
396                                       sizeof(NumaInformation),
397                                       &Length);
398     if (!NT_SUCCESS(Status))
399     {
400         BaseSetLastNTError(Status);
401         return FALSE;
402     }
403 
404     /* Validate input node number */
405     if (Node > NumaInformation.HighestNodeNumber)
406     {
407         SetLastError(ERROR_INVALID_PARAMETER);
408         return FALSE;
409     }
410 
411     /* Return available memory for that node */
412     *AvailableBytes = NumaInformation.AvailableMemory[Node];
413     return TRUE;
414 }
415 
416 /*
417  * @unimplemented
418  */
419 DWORD
420 WINAPI
421 GetFirmwareEnvironmentVariableW(IN LPCWSTR lpName,
422                                 IN LPCWSTR lpGuid,
423                                 IN PVOID pValue,
424                                 IN DWORD nSize)
425 {
426     STUB;
427     return 0;
428 }
429 
430 /*
431  * @unimplemented
432  */
433 BOOL
434 WINAPI
435 SetFirmwareEnvironmentVariableW(IN LPCWSTR lpName,
436                                 IN LPCWSTR lpGuid,
437                                 IN PVOID pValue,
438                                 IN DWORD nSize)
439 {
440     STUB;
441     return 0;
442 }
443 
444 /*
445  * @unimplemented
446  */
447 DWORD
448 WINAPI
449 GetFirmwareEnvironmentVariableA(IN LPCSTR lpName,
450                                 IN LPCSTR lpGuid,
451                                 IN PVOID pValue,
452                                 IN DWORD nSize)
453 {
454     STUB;
455     return 0;
456 }
457 
458 /*
459  * @unimplemented
460  */
461 BOOL
462 WINAPI
463 SetFirmwareEnvironmentVariableA(IN LPCSTR lpName,
464                                 IN LPCSTR lpGuid,
465                                 IN PVOID pValue,
466                                 IN DWORD nSize)
467 {
468     STUB;
469     return 0;
470 }
471 
472 /**
473  * @name EnumSystemFirmwareTables
474  * @implemented
475  *
476  * Obtains firmware table identifiers.
477  * https://msdn.microsoft.com/en-us/library/windows/desktop/ms724259(v=vs.85).aspx
478  *
479  * @param FirmwareTableProviderSignature
480  * Can be either ACPI, FIRM, or RSMB.
481  *
482  * @param pFirmwareTableBuffer
483  * Pointer to the output buffer, can be NULL.
484  *
485  * @param BufferSize
486  * Size of the output buffer.
487  *
488  * @return
489  * Actual size of the data in case of success, 0 otherwise.
490  *
491  * @remarks
492  * Data would be written to buffer only if the specified size is
493  * larger or equal to the actual size, in the other case Last Error
494  * value would be set to ERROR_INSUFFICIENT_BUFFER.
495  * In case of incorrect provider signature, Last Error value would be
496  * set to ERROR_INVALID_FUNCTION.
497  *
498  */
499 UINT
500 WINAPI
501 EnumSystemFirmwareTables(IN DWORD FirmwareTableProviderSignature,
502                          OUT PVOID pFirmwareTableBuffer,
503                          IN DWORD BufferSize)
504 {
505     return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
506                                    0,
507                                    pFirmwareTableBuffer,
508                                    BufferSize,
509                                    SystemFirmwareTable_Enumerate);
510 }
511 
512 /**
513  * @name GetSystemFirmwareTable
514  * @implemented
515  *
516  * Obtains the firmware table data.
517  * https://msdn.microsoft.com/en-us/library/windows/desktop/ms724379(v=vs.85).aspx
518  *
519  * @param FirmwareTableProviderSignature
520  * Can be either ACPI, FIRM, or RSMB.
521  *
522  * @param FirmwareTableID
523  * Correct table identifier.
524  *
525  * @param pFirmwareTableBuffer
526  * Pointer to the output buffer, can be NULL.
527  *
528  * @param BufferSize
529  * Size of the output buffer.
530  *
531  * @return
532  * Actual size of the data in case of success, 0 otherwise.
533  *
534  * @remarks
535  * Data would be written to buffer only if the specified size is
536  * larger or equal to the actual size, in the other case Last Error
537  * value would be set to ERROR_INSUFFICIENT_BUFFER.
538  * In case of incorrect provider signature, Last Error value would be
539  * set to ERROR_INVALID_FUNCTION.
540  * Also Last Error value becomes ERROR_NOT_FOUND if incorrect
541  * table identifier was specified along with ACPI provider, and
542  * ERROR_INVALID_PARAMETER along with FIRM provider. The RSMB provider
543  * accepts any table identifier.
544  *
545  */
546 UINT
547 WINAPI
548 GetSystemFirmwareTable(IN DWORD FirmwareTableProviderSignature,
549                        IN DWORD FirmwareTableID,
550                        OUT PVOID pFirmwareTableBuffer,
551                        IN DWORD BufferSize)
552 {
553     return BaseQuerySystemFirmware(FirmwareTableProviderSignature,
554                                    FirmwareTableID,
555                                    pFirmwareTableBuffer,
556                                    BufferSize,
557                                    SystemFirmwareTable_Get);
558 }
559 
560 /*
561  * @unimplemented
562  */
563 BOOL
564 WINAPI
565 GetSystemFileCacheSize(OUT PSIZE_T lpMinimumFileCacheSize,
566                        OUT PSIZE_T lpMaximumFileCacheSize,
567                        OUT PDWORD lpFlags)
568 {
569     STUB;
570     return FALSE;
571 }
572 
573 /*
574  * @unimplemented
575  */
576 BOOL
577 WINAPI
578 SetSystemFileCacheSize(IN SIZE_T MinimumFileCacheSize,
579                        IN SIZE_T MaximumFileCacheSize,
580                        IN DWORD Flags)
581 {
582     STUB;
583     return FALSE;
584 }
585