Reactos

[NTOS:EX/KE][HALX86] Add support for NUMPROC, BOOTPROC, MAXPROC, ONECPU boot switches (#6024)

These SMP-specific switches allow to test and control configurations
with various number of CPUs on multiprocessor systems.

- NUMPROC: maximum number of logical processors that can be started
(including dynamically, not currently supported by ReactOS) at run-time.

- BOOTPROC: maximum number of logical processors that can be started at
boot-time.

- MAXPROC: forces the OS to report the maximum possible number of CPUs
as existing on the system.

- ONECPU (MP HAL-only boot switch): causes the HAL to only use one
(the boot) CPU on a multiprocessor system. Attempting to start other
processors will fail.

For more information, see:
https://www.geoffchappell.com/notes/windows/boot/bcd/osloader/numproc.htm
https://www.geoffchappell.com/notes/windows/license/processors.htm
https://rmscrypt.wordpress.com/2011/02/
https://codeinsecurity.wordpress.com/2022/04/07/cpu-socket-and-core-count-limits-in-windows-10-and-how-to-remove-them/

Generic references about BOOT.INI switches:
https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/boot-options-in-a-boot-ini-file
https://www.itprotoday.com/cloud-computing/what-switches-can-be-used-bootini
http://franck.kiechel.free.fr/dbr_eng/BootIni.htm

References about BCD options:
https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/bcdedit--set
http://www.mistyprojects.co.uk/documents/BCDEdit/files/commands.6.1.7601.htm#TYPES%20OSLOADER

+90 -6
+9
hal/halx86/generic/halinit.c
··· 14 14 15 15 /* GLOBALS *******************************************************************/ 16 16 17 + //#ifdef CONFIG_SMP // FIXME: Reenable conditional once HAL is consistently compiled for SMP mode 18 + BOOLEAN HalpOnlyBootProcessor; 19 + //#endif 17 20 BOOLEAN HalpPciLockSettings; 18 21 19 22 /* PRIVATE FUNCTIONS *********************************************************/ ··· 29 32 { 30 33 /* Read the command line */ 31 34 PCSTR CommandLine = LoaderBlock->LoadOptions; 35 + 36 + //#ifdef CONFIG_SMP // FIXME: Reenable conditional once HAL is consistently compiled for SMP mode 37 + /* Check whether we should only start one CPU */ 38 + if (strstr(CommandLine, "ONECPU")) 39 + HalpOnlyBootProcessor = TRUE; 40 + //#endif 32 41 33 42 /* Check if PCI is locked */ 34 43 if (strstr(CommandLine, "PCILOCK"))
+7
hal/halx86/smp/i386/spinup.c
··· 16 16 17 17 /* GLOBALS *******************************************************************/ 18 18 19 + extern BOOLEAN HalpOnlyBootProcessor; 20 + 19 21 extern PPROCESSOR_IDENTITY HalpProcessorIdentity; 20 22 extern PHYSICAL_ADDRESS HalpLowStubPhysicalAddress; 21 23 extern PVOID HalpLowStub; ··· 88 90 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock, 89 91 _In_ PKPROCESSOR_STATE ProcessorState) 90 92 { 93 + /* Bail out if we only use the boot CPU */ 94 + if (HalpOnlyBootProcessor) 95 + return FALSE; 96 + 97 + /* Bail out if we have started all available CPUs */ 91 98 if (HalpStartedProcessorCount == HalpApicInfoTable.ProcessorCount) 92 99 return FALSE; 93 100
+28
ntoskrnl/ex/init.c
··· 1559 1559 } 1560 1560 1561 1561 #ifdef CONFIG_SMP 1562 + /* 1563 + * IMPORTANT NOTE: 1564 + * Because ReactOS is a "nice" OS, we do not care _at all_ 1565 + * about any number of registered/licensed processors: 1566 + * no usage of KeRegisteredProcessors nor KeLicensedProcessors. 1567 + */ 1568 + if (CommandLine) 1569 + { 1570 + PSTR Option; 1571 + 1572 + /* Check for NUMPROC: maximum number of logical processors 1573 + * that can be started (including dynamically) at run-time */ 1574 + Option = strstr(CommandLine, "NUMPROC"); 1575 + if (Option) Option = strstr(Option, "="); 1576 + if (Option) KeNumprocSpecified = atol(Option + 1); 1577 + 1578 + /* Check for BOOTPROC (NT6+ and ReactOS): maximum number 1579 + * of logical processors that can be started at boot-time */ 1580 + Option = strstr(CommandLine, "BOOTPROC"); 1581 + if (Option) Option = strstr(Option, "="); 1582 + if (Option) KeBootprocSpecified = atol(Option + 1); 1583 + 1584 + /* Check for MAXPROC (NT6+ and ReactOS): forces the kernel to report 1585 + * as existing the maximum number of processors that can be handled */ 1586 + if (strstr(CommandLine, "MAXPROC")) 1587 + KeMaximumProcessors = MAXIMUM_PROCESSORS; 1588 + } 1589 + 1562 1590 /* Start Application Processors */ 1563 1591 KeStartAllProcessors(); 1564 1592 #endif
+7 -2
ntoskrnl/include/internal/ke.h
··· 90 90 IN ULONG Length 91 91 ); 92 92 93 - extern KAFFINITY KeActiveProcessors; 94 93 extern PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead; 95 94 extern KSPIN_LOCK KiNmiCallbackListLock; 96 95 extern PVOID KeUserApcDispatcher; ··· 104 103 extern USHORT KeProcessorLevel; 105 104 extern USHORT KeProcessorRevision; 106 105 extern ULONG64 KeFeatureBits; 106 + extern KAFFINITY KeActiveProcessors; 107 + extern PKPRCB KiProcessorBlock[]; 108 + #ifdef CONFIG_SMP 109 + extern ULONG KeMaximumProcessors; 110 + extern ULONG KeNumprocSpecified; 111 + extern ULONG KeBootprocSpecified; 112 + #endif 107 113 extern KNODE KiNode0; 108 114 extern PKNODE KeNodeBlock[1]; 109 115 extern UCHAR KeNumberNodes; ··· 136 142 extern LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead; 137 143 extern LIST_ENTRY KiStackInSwapListHead; 138 144 extern KEVENT KiSwapEvent; 139 - extern PKPRCB KiProcessorBlock[]; 140 145 extern KAFFINITY KiIdleSummary; 141 146 extern PVOID KeUserApcDispatcher; 142 147 extern PVOID KeUserCallbackDispatcher;
+20 -3
ntoskrnl/ke/i386/mproc.c
··· 9 9 /* INCLUDES *****************************************************************/ 10 10 11 11 #include <ntoskrnl.h> 12 + 12 13 #define NDEBUG 13 14 #include <debug.h> 14 15 ··· 38 39 KeStartAllProcessors(VOID) 39 40 { 40 41 PVOID KernelStack, DPCStack; 41 - ULONG ProcessorCount = 0; 42 42 PAPINFO APInfo; 43 + ULONG ProcessorCount; 44 + ULONG MaximumProcessors; 43 45 44 - while (TRUE) 46 + /* NOTE: NT6+ HAL exports HalEnumerateProcessors() and 47 + * HalQueryMaximumProcessorCount() that help determining 48 + * the number of detected processors on the system. */ 49 + MaximumProcessors = KeMaximumProcessors; 50 + 51 + /* Limit the number of processors we can start at run-time */ 52 + if (KeNumprocSpecified) 53 + MaximumProcessors = min(MaximumProcessors, KeNumprocSpecified); 54 + 55 + /* Limit also the number of processors we can start during boot-time */ 56 + if (KeBootprocSpecified) 57 + MaximumProcessors = min(MaximumProcessors, KeBootprocSpecified); 58 + 59 + // TODO: Support processor nodes 60 + 61 + /* Start ProcessorCount at 1 because we already have the boot CPU */ 62 + for (ProcessorCount = 1; ProcessorCount < MaximumProcessors; ++ProcessorCount) 45 63 { 46 - ProcessorCount++; 47 64 KernelStack = NULL; 48 65 DPCStack = NULL; 49 66
+19 -1
ntoskrnl/ke/processor.c
··· 13 13 14 14 /* GLOBALS *******************************************************************/ 15 15 16 + KAFFINITY KeActiveProcessors = 0; 17 + 18 + /* Number of processors */ 16 19 CCHAR KeNumberProcessors = 0; 17 - KAFFINITY KeActiveProcessors = 0; 20 + 21 + #ifdef CONFIG_SMP 22 + 23 + /* Theoretical maximum number of processors that can be handled. 24 + * Set once at run-time. Returned by KeQueryMaximumProcessorCount(). */ 25 + ULONG KeMaximumProcessors = MAXIMUM_PROCESSORS; 26 + 27 + /* Maximum number of logical processors that can be started 28 + * (including dynamically) at run-time. If 0: do not perform checks. */ 29 + ULONG KeNumprocSpecified = 0; 30 + 31 + /* Maximum number of logical processors that can be started 32 + * at boot-time. If 0: do not perform checks. */ 33 + ULONG KeBootprocSpecified = 0; 34 + 35 + #endif // CONFIG_SMP 18 36 19 37 /* FUNCTIONS *****************************************************************/ 20 38