ReactOS 0.4.16-dev-983-g23ad936
mproc.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Architecture specific source file to hold multiprocessor functions
5 * COPYRIGHT: Copyright 2023 Justin Miller <justin.miller@reactos.org>
6 * Copyright 2023 Victor Perevertkin <victor.perevertkin@reactos.org>
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include <ntoskrnl.h>
12
13#define NDEBUG
14#include <debug.h>
15
16typedef struct _APINFO
17{
21 KIPCR Pcr;
23 KTSS Tss;
24 KTSS TssDoubleFault;
25 KTSS TssNMI;
27
28typedef struct _AP_SETUP_STACK
29{
32} AP_SETUP_STACK, *PAP_SETUP_STACK; // Note: expected layout only for 32-bit x86
33
34/* FUNCTIONS *****************************************************************/
35
36CODE_SEG("INIT")
37VOID
40{
41 PVOID KernelStack, DPCStack;
42 PAPINFO APInfo;
44 ULONG MaximumProcessors;
45
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)
63 {
64 KernelStack = NULL;
65 DPCStack = NULL;
66
67 // Allocate structures for a new CPU.
68 APInfo = ExAllocatePoolZero(NonPagedPool, sizeof(*APInfo), TAG_KERNEL);
69 if (!APInfo)
70 break;
71 ASSERT(ALIGN_DOWN_POINTER_BY(APInfo, PAGE_SIZE) == APInfo);
72
73 KernelStack = MmCreateKernelStack(FALSE, 0);
74 if (!KernelStack)
75 break;
76
77 DPCStack = MmCreateKernelStack(FALSE, 0);
78 if (!DPCStack)
79 break;
80
81 // Initalize a new PCR for the specific AP
83 &APInfo->Pcr,
84 &APInfo->Idt[0],
85 &APInfo->Gdt[0],
86 &APInfo->Tss,
87 (PKTHREAD)&APInfo->Thread,
88 DPCStack);
89
90 // Prepare descriptor tables
91 KDESCRIPTOR bspGdt, bspIdt;
92 __sgdt(&bspGdt.Limit);
93 __sidt(&bspIdt.Limit);
94 RtlCopyMemory(&APInfo->Gdt, (PVOID)bspGdt.Base, bspGdt.Limit + 1);
95 RtlCopyMemory(&APInfo->Idt, (PVOID)bspIdt.Base, bspIdt.Limit + 1);
96
97 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_R0_PCR), (ULONG_PTR)&APInfo->Pcr);
98 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_DF_TSS), (ULONG_PTR)&APInfo->TssDoubleFault);
99 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_NMI_TSS), (ULONG_PTR)&APInfo->TssNMI);
100
101 KiSetGdtDescriptorBase(KiGetGdtEntry(&APInfo->Gdt, KGDT_TSS), (ULONG_PTR)&APInfo->Tss);
102 // Clear TSS Busy flag (aka set the type to "TSS (Available)")
103 KiGetGdtEntry(&APInfo->Gdt, KGDT_TSS)->HighWord.Bits.Type = I386_TSS;
104
105 APInfo->TssDoubleFault.Esp0 = (ULONG_PTR)&APInfo->NMIStackData;
106 APInfo->TssDoubleFault.Esp = (ULONG_PTR)&APInfo->NMIStackData;
107
108 APInfo->TssNMI.Esp0 = (ULONG_PTR)&APInfo->NMIStackData;
109 APInfo->TssNMI.Esp = (ULONG_PTR)&APInfo->NMIStackData;
110
111 // Fill the processor state
112 PKPROCESSOR_STATE ProcessorState = &APInfo->Pcr.Prcb->ProcessorState;
113 RtlZeroMemory(ProcessorState, sizeof(*ProcessorState));
114
115 ProcessorState->SpecialRegisters.Cr0 = __readcr0();
116 ProcessorState->SpecialRegisters.Cr3 = __readcr3();
117 ProcessorState->SpecialRegisters.Cr4 = __readcr4();
118
119 ProcessorState->ContextFrame.SegCs = KGDT_R0_CODE;
120 ProcessorState->ContextFrame.SegDs = KGDT_R3_DATA;
121 ProcessorState->ContextFrame.SegEs = KGDT_R3_DATA;
122 ProcessorState->ContextFrame.SegSs = KGDT_R0_DATA;
123 ProcessorState->ContextFrame.SegFs = KGDT_R0_PCR;
124
125 ProcessorState->SpecialRegisters.Gdtr.Base = (ULONG_PTR)APInfo->Gdt;
126 ProcessorState->SpecialRegisters.Gdtr.Limit = sizeof(APInfo->Gdt) - 1;
127 ProcessorState->SpecialRegisters.Idtr.Base = (ULONG_PTR)APInfo->Idt;
128 ProcessorState->SpecialRegisters.Idtr.Limit = sizeof(APInfo->Idt) - 1;
129
130 ProcessorState->SpecialRegisters.Tr = KGDT_TSS;
131
132 ProcessorState->ContextFrame.Esp = (ULONG_PTR)KernelStack;
133 ProcessorState->ContextFrame.Eip = (ULONG_PTR)KiSystemStartup;
134 ProcessorState->ContextFrame.EFlags = __readeflags() & ~EFLAGS_INTERRUPT_MASK;
135
136 ProcessorState->ContextFrame.Esp = (ULONG)((ULONG_PTR)ProcessorState->ContextFrame.Esp - sizeof(AP_SETUP_STACK));
137 PAP_SETUP_STACK ApStack = (PAP_SETUP_STACK)ProcessorState->ContextFrame.Esp;
138 ApStack->KxLoaderBlock = KeLoaderBlock;
139 ApStack->ReturnAddr = NULL;
140
141 // Update the LOADER_PARAMETER_BLOCK structure for the new processor
142 KeLoaderBlock->KernelStack = (ULONG_PTR)KernelStack;
143 KeLoaderBlock->Prcb = (ULONG_PTR)&APInfo->Pcr.Prcb;
144 KeLoaderBlock->Thread = (ULONG_PTR)&APInfo->Pcr.Prcb->IdleThread;
145
146 // Start the CPU
147 DPRINT("Attempting to Start a CPU with number: %lu\n", ProcessorCount);
148 if (!HalStartNextProcessor(KeLoaderBlock, ProcessorState))
149 {
150 break;
151 }
152
153 // And wait for it to start
154 while (KeLoaderBlock->Prcb != 0)
155 {
156 //TODO: Add a time out so we don't wait forever
159 }
160 }
161
162 // The last CPU didn't start - clean the data
164
165 if (APInfo)
167 if (KernelStack)
168 MmDeleteKernelStack(KernelStack, FALSE);
169 if (DPCStack)
170 MmDeleteKernelStack(DPCStack, FALSE);
171
172 DPRINT1("KeStartAllProcessors: Successful AP startup count is %lu\n", ProcessorCount);
173}
#define CODE_SEG(...)
unsigned char UINT8
FORCEINLINE PKGDTENTRY64 KiGetGdtEntry(PVOID pGdt, USHORT Selector)
Definition: intrin_i.h:13
FORCEINLINE VOID KiSetGdtDescriptorBase(PKGDTENTRY Entry, ULONG64 Base)
Definition: intrin_i.h:30
VOID NTAPI KeStartAllProcessors(VOID)
Definition: mproc.c:20
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
int ProcessorCount
Definition: bus.c:58
#define ULONG_PTR
Definition: config.h:101
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define NonPagedPool
Definition: env_spec_w32.h:307
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
BOOLEAN NTAPI HalStartNextProcessor(IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PKPROCESSOR_STATE ProcessorState)
Definition: processor.c:71
struct _AP_SETUP_STACK AP_SETUP_STACK
struct _APINFO * PAPINFO
struct _APINFO APINFO
struct _AP_SETUP_STACK * PAP_SETUP_STACK
__INTRIN_INLINE unsigned long __readcr3(void)
Definition: intrin_x86.h:1832
__INTRIN_INLINE unsigned long __readcr4(void)
Definition: intrin_x86.h:1839
__INTRIN_INLINE unsigned long __readcr0(void)
Definition: intrin_x86.h:1818
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1688
__INTRIN_INLINE void __sidt(void *Destination)
Definition: intrin_x86.h:2046
PLOADER_PARAMETER_BLOCK KeLoaderBlock
Definition: krnlinit.c:28
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
FORCEINLINE PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
#define min(a, b)
Definition: monoChain.cc:55
#define I386_TSS
Definition: ketypes.h:110
#define DOUBLE_FAULT_STACK_SIZE
Definition: ketypes.h:86
#define KGDT_R3_DATA
Definition: ketypes.h:126
#define KGDT_NMI_TSS
Definition: ketypes.h:133
#define KGDT_TSS
Definition: ketypes.h:127
#define KGDT_R0_PCR
Definition: ketypes.h:128
#define KGDT_DF_TSS
Definition: ketypes.h:132
#define KGDT_R0_CODE
Definition: ketypes.h:123
#define KGDT_R0_DATA
Definition: ketypes.h:124
#define DECLSPEC_ALIGN(x)
Definition: ntbasedef.h:259
VOID NTAPI KiInitializePcr(IN ULONG ProcessorNumber, IN PKIPCR Pcr, IN PKIDTENTRY Idt, IN PKGDTENTRY Gdt, IN PKTSS Tss, IN PKTHREAD IdleThread, IN PVOID DpcStack)
Definition: kiinit.c:284
DECLSPEC_NORETURN VOID NTAPI KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
Definition: kiinit.c:476
VOID NTAPI MmDeleteKernelStack(PVOID Stack, BOOLEAN GuiStack)
PVOID NTAPI MmCreateKernelStack(BOOLEAN GuiStack, UCHAR Node)
#define YieldProcessor
Definition: ke.h:48
FORCEINLINE VOID KeMemoryBarrier(VOID)
Definition: ke.h:58
#define DPRINT
Definition: sndvol32.h:73
Definition: mproc.c:17
PVOID ReturnAddr
Definition: mproc.c:30
PVOID KxLoaderBlock
Definition: mproc.c:31
ULONG Esp
Definition: nt_native.h:1479
ULONG SegFs
Definition: nt_native.h:1454
ULONG SegSs
Definition: nt_native.h:1480
ULONG Eip
Definition: nt_native.h:1476
ULONG SegCs
Definition: nt_native.h:1477
ULONG SegDs
Definition: nt_native.h:1456
ULONG EFlags
Definition: nt_native.h:1478
ULONG SegEs
Definition: nt_native.h:1455
ULONG Base
Definition: ketypes.h:450
USHORT Limit
Definition: ketypes.h:449
PVOID Base
Definition: ketypes.h:580
USHORT Limit
Definition: ketypes.h:579
KSPECIAL_REGISTERS SpecialRegisters
Definition: ketypes.h:624
CONTEXT ContextFrame
Definition: ketypes.h:625
KDESCRIPTOR Gdtr
Definition: ketypes.h:600
KDESCRIPTOR Idtr
Definition: ketypes.h:601
Definition: ketypes.h:850
ULONG_PTR KernelStack
Definition: arc.h:543
ULONG_PTR Prcb
Definition: arc.h:544
ULONG_PTR Thread
Definition: arc.h:546
#define TAG_KERNEL
Definition: tag.h:42
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82
struct _KGDTENTRY64::@2394::@2396::@2399 Bits