- Add loop around the KiFreezeExecutionLock before continuing OS boot.
[reactos.git] / reactos / ntoskrnl / ke / i386 / kiinit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/kiinit.c
5 * PURPOSE: Kernel Initialization for x86 CPUs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 #include <intrin.h>
15
16 /* GLOBALS *******************************************************************/
17
18 VOID
19 FASTCALL
20 KiIdleLoop(VOID);
21
22 /* Spinlocks used only on X86 */
23 KSPIN_LOCK KiFreezeExecutionLock;
24 KSPIN_LOCK Ki486CompatibilityLock;
25
26 /* FUNCTIONS *****************************************************************/
27
28 VOID
29 NTAPI
30 KiInitializePcr(IN ULONG ProcessorNumber,
31 IN PKIPCR Pcr,
32 IN PKIDTENTRY Idt,
33 IN PKGDTENTRY Gdt,
34 IN PKTSS Tss,
35 IN PKTHREAD IdleThread,
36 IN PVOID DpcStack)
37 {
38 /* Setup the TIB */
39 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
40 Pcr->NtTib.StackBase = 0;
41 Pcr->NtTib.StackLimit = 0;
42 Pcr->NtTib.Self = 0;
43
44 /* Set the Current Thread */
45 Pcr->PrcbData.CurrentThread = IdleThread;
46
47 /* Set pointers to ourselves */
48 Pcr->Self = (PKPCR)Pcr;
49 Pcr->Prcb = &Pcr->PrcbData;
50
51 /* Set the PCR Version */
52 Pcr->MajorVersion = PCR_MAJOR_VERSION;
53 Pcr->MinorVersion = PCR_MINOR_VERSION;
54
55 /* Set the PCRB Version */
56 Pcr->PrcbData.MajorVersion = 1;
57 Pcr->PrcbData.MinorVersion = 1;
58
59 /* Set the Build Type */
60 Pcr->PrcbData.BuildType = 0;
61
62 /* Set the Processor Number and current Processor Mask */
63 Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
64 Pcr->PrcbData.SetMember = 1 << ProcessorNumber;
65
66 /* Set the PRCB for this Processor */
67 KiProcessorBlock[ProcessorNumber] = Pcr->Prcb;
68
69 /* Start us out at PASSIVE_LEVEL */
70 Pcr->Irql = PASSIVE_LEVEL;
71
72 /* Set the GDI, IDT, TSS and DPC Stack */
73 Pcr->GDT = (PVOID)Gdt;
74 Pcr->IDT = Idt;
75 Pcr->TSS = Tss;
76 Pcr->PrcbData.DpcStack = DpcStack;
77 }
78
79 VOID
80 NTAPI
81 KiInitializeKernel(IN PKPROCESS InitProcess,
82 IN PKTHREAD InitThread,
83 IN PVOID IdleStack,
84 IN PKPRCB Prcb,
85 IN CCHAR Number,
86 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
87 {
88 BOOLEAN NpxPresent;
89 ULONG FeatureBits;
90 LARGE_INTEGER PageDirectory;
91 PVOID DpcStack;
92
93 /* Detect and set the CPU Type */
94 KiSetProcessorType();
95
96 /* Set CR0 features based on detected CPU */
97 KiSetCR0Bits();
98
99 /* Check if an FPU is present */
100 NpxPresent = KiIsNpxPresent();
101
102 /* Initialize the Power Management Support for this PRCB */
103 PoInitializePrcb(Prcb);
104
105 /* Bugcheck if this is a 386 CPU */
106 if (Prcb->CpuType == 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
107
108 /* Get the processor features for the CPU */
109 FeatureBits = KiGetFeatureBits();
110
111 /* Save feature bits */
112 Prcb->FeatureBits = FeatureBits;
113
114 /* Get cache line information for this CPU */
115 KiGetCacheInformation();
116
117 /* Initialize spinlocks and DPC data */
118 KiInitSpinLocks(Prcb, Number);
119
120 /* Check if this is the Boot CPU */
121 if (!Number)
122 {
123 /* Set Node Data */
124 KeNodeBlock[0] = &KiNode0;
125 Prcb->ParentNode = KeNodeBlock[0];
126 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
127
128 /* Set boot-level flags */
129 KeI386NpxPresent = NpxPresent;
130 KeI386CpuType = Prcb->CpuType;
131 KeI386CpuStep = Prcb->CpuStep;
132 KeProcessorArchitecture = 0;
133 KeProcessorLevel = (USHORT)Prcb->CpuType;
134 if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
135 KeFeatureBits = FeatureBits;
136 KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
137 KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
138
139 /* Set the current MP Master KPRCB to the Boot PRCB */
140 Prcb->MultiThreadSetMaster = Prcb;
141
142 /* Lower to APC_LEVEL */
143 KfLowerIrql(APC_LEVEL);
144
145 /* Initialize some spinlocks */
146 KeInitializeSpinLock(&KiFreezeExecutionLock);
147 KeInitializeSpinLock(&Ki486CompatibilityLock);
148
149 /* Initialize portable parts of the OS */
150 KiInitSystem();
151
152 /* Initialize the Idle Process and the Process Listhead */
153 InitializeListHead(&KiProcessListHead);
154 PageDirectory.QuadPart = 0;
155 KeInitializeProcess(InitProcess,
156 0,
157 0xFFFFFFFF,
158 &PageDirectory,
159 FALSE);
160 InitProcess->QuantumReset = MAXCHAR;
161 }
162 else
163 {
164 /* FIXME */
165 DPRINT1("SMP Boot support not yet present\n");
166 }
167
168 /* Setup the Idle Thread */
169 KeInitializeThread(InitProcess,
170 InitThread,
171 NULL,
172 NULL,
173 NULL,
174 NULL,
175 NULL,
176 IdleStack);
177 InitThread->NextProcessor = Number;
178 InitThread->Priority = HIGH_PRIORITY;
179 InitThread->State = Running;
180 InitThread->Affinity = 1 << Number;
181 InitThread->WaitIrql = DISPATCH_LEVEL;
182 InitProcess->ActiveProcessors = 1 << Number;
183
184 /* HACK for MmUpdatePageDir */
185 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
186
187 /* Set up the thread-related fields in the PRCB */
188 Prcb->CurrentThread = InitThread;
189 Prcb->NextThread = NULL;
190 Prcb->IdleThread = InitThread;
191
192 /* Initialize the Kernel Executive */
193 ExpInitializeExecutive();
194
195 /* Only do this on the boot CPU */
196 if (!Number)
197 {
198 /* Calculate the time reciprocal */
199 KiTimeIncrementReciprocal =
200 KiComputeReciprocal(KeMaximumIncrement,
201 &KiTimeIncrementShiftCount);
202
203 /* Update DPC Values in case they got updated by the executive */
204 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
205 Prcb->MinimumDpcRate = KiMinimumDpcRate;
206 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
207
208 /* Allocate the DPC Stack */
209 DpcStack = MmCreateKernelStack(FALSE);
210 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
211 Prcb->DpcStack = DpcStack;
212
213 /* Allocate the IOPM save area. */
214 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
215 PAGE_SIZE * 2,
216 TAG('K', 'e', ' ', ' '));
217 if (!Ki386IopmSaveArea)
218 {
219 /* Bugcheck. We need this for V86/VDM support. */
220 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
221 }
222 }
223
224 /* Raise to Dispatch */
225 KfRaiseIrql(DISPATCH_LEVEL);
226
227 /* Set the Idle Priority to 0. This will jump into Phase 1 */
228 KeSetPriorityThread(InitThread, 0);
229 }
230
231 VOID
232 NTAPI
233 KiGetMachineBootPointers(IN PKGDTENTRY *Gdt,
234 IN PKIDTENTRY *Idt,
235 IN PKIPCR *Pcr,
236 IN PKTSS *Tss)
237 {
238 KDESCRIPTOR GdtDescriptor, IdtDescriptor;
239 KGDTENTRY TssSelector, PcrSelector;
240 ULONG Tr, Fs;
241
242 /* Get GDT and IDT descriptors */
243 Ke386GetGlobalDescriptorTable(GdtDescriptor);
244 Ke386GetInterruptDescriptorTable(IdtDescriptor);
245
246 /* Save IDT and GDT */
247 *Gdt = (PKGDTENTRY)GdtDescriptor.Base;
248 *Idt = (PKIDTENTRY)IdtDescriptor.Base;
249
250 /* Get TSS and FS Selectors */
251 Ke386GetTr(&Tr);
252 if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
253 Fs = Ke386GetFs();
254
255 /* Get PCR Selector, mask it and get its GDT Entry */
256 PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK));
257
258 /* Get the KPCR itself */
259 *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow |
260 PcrSelector.HighWord.Bytes.BaseMid << 16 |
261 PcrSelector.HighWord.Bytes.BaseHi << 24);
262
263 /* Get TSS Selector, mask it and get its GDT Entry */
264 TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK));
265
266 /* Get the KTSS itself */
267 *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow |
268 TssSelector.HighWord.Bytes.BaseMid << 16 |
269 TssSelector.HighWord.Bytes.BaseHi << 24);
270 }
271
272 VOID
273 NTAPI
274 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
275 {
276 ULONG Cpu;
277 PKTHREAD InitialThread;
278 PVOID InitialStack;
279 PKGDTENTRY Gdt;
280 PKIDTENTRY Idt;
281 PKTSS Tss;
282 PKIPCR Pcr;
283
284 /* Save the loader block and get the current CPU */
285 KeLoaderBlock = LoaderBlock;
286 Cpu = KeNumberProcessors;
287 if (!Cpu)
288 {
289 /* If this is the boot CPU, set FS and the CPU Number*/
290 Ke386SetFs(KGDT_R0_PCR);
291 KeGetPcr()->Number = Cpu;
292
293 /* Set the initial stack and idle thread as well */
294 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
295 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
296 }
297
298 /* Save the initial thread and stack */
299 InitialStack = (PVOID)LoaderBlock->KernelStack;
300 InitialThread = (PKTHREAD)LoaderBlock->Thread;
301
302 /* Clean the APC List Head */
303 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
304
305 /* Initialize the machine type */
306 KiInitializeMachineType();
307
308 /* Skip initial setup if this isn't the Boot CPU */
309 if (Cpu) goto AppCpuInit;
310
311 /* Get GDT, IDT, PCR and TSS pointers */
312 KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
313
314 /* Setup the TSS descriptors and entries */
315 Ki386InitializeTss(Tss, Idt);
316
317 /* Initialize the PCR */
318 RtlZeroMemory(Pcr, PAGE_SIZE);
319 KiInitializePcr(Cpu,
320 Pcr,
321 Idt,
322 Gdt,
323 Tss,
324 InitialThread,
325 KiDoubleFaultStack);
326
327 /* Set us as the current process */
328 InitialThread->ApcState.Process = &KiInitialProcess.Pcb;
329
330 /* Clear DR6/7 to cleanup bootloader debugging */
331 __writefsdword(KPCR_DR6, 0);
332 __writefsdword(KPCR_DR7, 0);
333
334 /* Load Ring 3 selectors for DS/ES */
335 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
336 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
337
338 AppCpuInit:
339 /* Loop until we can release the freeze lock */
340 do
341 {
342 /* Loop until execution can continue */
343 while (KiFreezeExecutionLock == 1);
344 } while(InterlockedBitTestAndSet(&KiFreezeExecutionLock, 0));
345
346 /* Setup CPU-related fields */
347 __writefsdword(KPCR_NUMBER, Cpu);
348 __writefsdword(KPCR_SET_MEMBER, 1 << Cpu);
349 __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu);
350 __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu);
351
352 /* Initialize the Processor with HAL */
353 HalInitializeProcessor(Cpu, KeLoaderBlock);
354
355 /* Set active processors */
356 KeActiveProcessors |= Pcr->SetMember;
357 KeNumberProcessors++;
358
359 /* Check if this is the boot CPU */
360 if (!Cpu)
361 {
362 /* Initialize debugging system */
363 KdInitSystem (0, KeLoaderBlock);
364
365 /* Check for break-in */
366 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
367 }
368
369 /* Raise to HIGH_LEVEL */
370 KfRaiseIrql(HIGH_LEVEL);
371
372 /* Call main kernel initialization */
373 KiInitializeKernel(&KiInitialProcess.Pcb,
374 InitialThread,
375 InitialStack,
376 &Pcr->PrcbData, //(PKPRCB)__readfsdword(KPCR_PRCB),
377 Cpu,
378 LoaderBlock);
379
380 /* Set the priority of this thread to 0 */
381 KeGetCurrentThread()->Priority = 0;
382
383 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
384 _enable();
385 KfLowerIrql(DISPATCH_LEVEL);
386
387 /* Set the right wait IRQL */
388 KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
389
390 /* Set idle thread as running on UP builds */
391 #ifndef CONFIG_SMP
392 KeGetCurrentThread()->State = Running;
393 #endif
394
395 /* Jump into the idle loop */
396 KiIdleLoop();
397 }
398