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 _Success_(return > 0) 428 DWORD 429 WINAPI 430 GetFirmwareEnvironmentVariableExA( 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 437 BOOL 438 WINAPI 439 SetFirmwareEnvironmentVariableExW( 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 446 BOOL 447 WINAPI 448 SetFirmwareEnvironmentVariableExA( 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) 456 DWORD 457 WINAPI 458 GetFirmwareEnvironmentVariableW( 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 467 _Success_(return > 0) 468 DWORD 469 WINAPI 470 GetFirmwareEnvironmentVariableA( 471 _In_ LPCSTR lpName, 472 _In_ LPCSTR lpGuid, 473 _Out_writes_bytes_to_opt_(nSize, return) PVOID pBuffer, 474 _In_ DWORD nSize) 475 { 476 return GetFirmwareEnvironmentVariableExA(lpName, lpGuid, pBuffer, nSize, NULL); 477 } 478 479 BOOL 480 WINAPI 481 SetFirmwareEnvironmentVariableW( 482 _In_ LPCWSTR lpName, 483 _In_ LPCWSTR lpGuid, 484 _In_reads_bytes_opt_(nSize) PVOID pValue, 485 _In_ DWORD nSize) 486 { 487 return SetFirmwareEnvironmentVariableExW(lpName, 488 lpGuid, 489 pValue, 490 nSize, 491 VARIABLE_ATTRIBUTE_NON_VOLATILE); 492 } 493 494 BOOL 495 WINAPI 496 SetFirmwareEnvironmentVariableA( 497 _In_ LPCSTR lpName, 498 _In_ LPCSTR lpGuid, 499 _In_reads_bytes_opt_(nSize) PVOID pValue, 500 _In_ DWORD nSize) 501 { 502 return SetFirmwareEnvironmentVariableExA(lpName, 503 lpGuid, 504 pValue, 505 nSize, 506 VARIABLE_ATTRIBUTE_NON_VOLATILE); 507 } 508 509 /** 510 * @name EnumSystemFirmwareTables 511 * @implemented 512 * 513 * Obtains firmware table identifiers. 514 * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-enumsystemfirmwaretables 515 * 516 * @param FirmwareTableProviderSignature 517 * Can be either ACPI, FIRM, or RSMB. 518 * 519 * @param pFirmwareTableBuffer 520 * Pointer to the output buffer, can be NULL. 521 * 522 * @param BufferSize 523 * Size of the output buffer. 524 * 525 * @return 526 * Actual size of the data in case of success, 0 otherwise. 527 * 528 * @remarks 529 * Data would be written to buffer only if the specified size is 530 * larger or equal to the actual size, in the other case Last Error 531 * value would be set to ERROR_INSUFFICIENT_BUFFER. 532 * In case of incorrect provider signature, Last Error value would be 533 * set to ERROR_INVALID_FUNCTION. 534 * 535 */ 536 UINT 537 WINAPI 538 EnumSystemFirmwareTables( 539 _In_ DWORD FirmwareTableProviderSignature, 540 _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableEnumBuffer, 541 _In_ DWORD BufferSize) 542 { 543 return BaseQuerySystemFirmware(FirmwareTableProviderSignature, 544 0, 545 pFirmwareTableEnumBuffer, 546 BufferSize, 547 SystemFirmwareTable_Enumerate); 548 } 549 550 /** 551 * @name GetSystemFirmwareTable 552 * @implemented 553 * 554 * Obtains the firmware table data. 555 * https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable 556 * 557 * @param FirmwareTableProviderSignature 558 * Can be either ACPI, FIRM, or RSMB. 559 * 560 * @param FirmwareTableID 561 * Correct table identifier. 562 * 563 * @param pFirmwareTableBuffer 564 * Pointer to the output buffer, can be NULL. 565 * 566 * @param BufferSize 567 * Size of the output buffer. 568 * 569 * @return 570 * Actual size of the data in case of success, 0 otherwise. 571 * 572 * @remarks 573 * Data would be written to buffer only if the specified size is 574 * larger or equal to the actual size, in the other case Last Error 575 * value would be set to ERROR_INSUFFICIENT_BUFFER. 576 * In case of incorrect provider signature, Last Error value would be 577 * set to ERROR_INVALID_FUNCTION. 578 * Also Last Error value becomes ERROR_NOT_FOUND if incorrect 579 * table identifier was specified along with ACPI provider, and 580 * ERROR_INVALID_PARAMETER along with FIRM provider. The RSMB provider 581 * accepts any table identifier. 582 * 583 */ 584 UINT 585 WINAPI 586 GetSystemFirmwareTable( 587 _In_ DWORD FirmwareTableProviderSignature, 588 _In_ DWORD FirmwareTableID, 589 _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer, 590 _In_ DWORD BufferSize) 591 { 592 return BaseQuerySystemFirmware(FirmwareTableProviderSignature, 593 FirmwareTableID, 594 pFirmwareTableBuffer, 595 BufferSize, 596 SystemFirmwareTable_Get); 597 } 598 599 /* 600 * @unimplemented 601 */ 602 BOOL 603 WINAPI 604 GetSystemFileCacheSize(OUT PSIZE_T lpMinimumFileCacheSize, 605 OUT PSIZE_T lpMaximumFileCacheSize, 606 OUT PDWORD lpFlags) 607 { 608 STUB; 609 return FALSE; 610 } 611 612 /* 613 * @unimplemented 614 */ 615 BOOL 616 WINAPI 617 SetSystemFileCacheSize(IN SIZE_T MinimumFileCacheSize, 618 IN SIZE_T MaximumFileCacheSize, 619 IN DWORD Flags) 620 { 621 STUB; 622 return FALSE; 623 } 624 625 /* 626 * @unimplemented 627 */ 628 LONG 629 WINAPI 630 GetCurrentPackageId(UINT32 *BufferLength, 631 BYTE *Buffer) 632 { 633 STUB; 634 return APPMODEL_ERROR_NO_PACKAGE; 635 } 636