- Fix KUSER_SHARED_DATA in winddk.h
[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 #define NTDDI_VERSION NTDDI_WS03SP1
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 /* Spinlocks used only on X86 */
19 KSPIN_LOCK KiFreezeExecutionLock;
20 KSPIN_LOCK Ki486CompatibilityLock;
21
22 /* FUNCTIONS *****************************************************************/
23
24 VOID
25 NTAPI
26 KiInitMachineDependent(VOID)
27 {
28 ULONG Protect;
29 ULONG CpuCount;
30 BOOLEAN FbCaching = FALSE;
31 NTSTATUS Status;
32 //ULONG ReturnLength;
33 ULONG i, Affinity;
34 PFX_SAVE_AREA FxSaveArea;
35 ULONG MXCsrMask = 0xFFBF, NewMask;
36
37 /* Check for large page support */
38 if (KeFeatureBits & KF_LARGE_PAGE)
39 {
40 /* FIXME: Support this */
41 DPRINT1("Your machine supports PGE but ReactOS doesn't yet.\n");
42 }
43
44 /* Check for global page support */
45 if (KeFeatureBits & KF_GLOBAL_PAGE)
46 {
47 /* Do an IPI to enable it on all CPUs */
48 CpuCount = KeNumberProcessors;
49 KeIpiGenericCall(Ki386EnableGlobalPage, (ULONG_PTR)&CpuCount);
50 }
51
52 /* Check for PAT and/or MTRR support */
53 if (KeFeatureBits & (KF_PAT | KF_MTRR))
54 {
55 /* FIXME: ROS HAL Doesn't initialize this! */
56 #if 1
57 Status = STATUS_UNSUCCESSFUL;
58 #else
59 /* Query the HAL to make sure we can use it */
60 Status = HalQuerySystemInformation(HalFrameBufferCachingInformation,
61 sizeof(BOOLEAN),
62 &FbCaching,
63 &ReturnLength);
64 #endif
65 if ((NT_SUCCESS(Status)) && (FbCaching))
66 {
67 /* We can't, disable it */
68 KeFeatureBits &= ~(KF_PAT | KF_MTRR);
69 }
70 }
71
72 /* Check for PAT support and enable it */
73 if (KeFeatureBits & KF_PAT) KiInitializePAT();
74
75 /* Assume no errata for now */
76 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = 0;
77
78 /* If there's no NPX, then we're emulating the FPU */
79 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] =
80 !KeI386NpxPresent;
81
82 /* Check if there's no NPX, so that we can disable associated features */
83 if (!KeI386NpxPresent)
84 {
85 /* Remove NPX-related bits */
86 KeFeatureBits &= ~(KF_XMMI64 | KF_XMMI | KF_FXSR | KF_MMX);
87
88 /* Disable kernel flags */
89 KeI386FxsrPresent = KeI386XMMIPresent = FALSE;
90
91 /* Disable processor features that might've been set until now */
92 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] =
93 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
94 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
95 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
96 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] = 0;
97 }
98
99 /* Check for CR4 support */
100 if (KeFeatureBits & KF_CR4)
101 {
102 /* Do an IPI call to enable the Debug Exceptions */
103 CpuCount = KeNumberProcessors;
104 KeIpiGenericCall(Ki386EnableDE, (ULONG_PTR)&CpuCount);
105 }
106
107 /* Check if FXSR was found */
108 if (KeFeatureBits & KF_FXSR)
109 {
110 /* Do an IPI call to enable the FXSR */
111 CpuCount = KeNumberProcessors;
112 KeIpiGenericCall(Ki386EnableFxsr, (ULONG_PTR)&CpuCount);
113
114 /* Check if XMM was found too */
115 if (KeFeatureBits & KF_XMMI)
116 {
117 /* Do an IPI call to enable XMMI exceptions */
118 CpuCount = KeNumberProcessors;
119 KeIpiGenericCall(Ki386EnableXMMIExceptions, (ULONG_PTR)&CpuCount);
120
121 /* FIXME: Implement and enable XMM Page Zeroing for Mm */
122
123 /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */
124 Protect = MmGetPageProtect(NULL, RtlPrefetchMemoryNonTemporal);
125 MmSetPageProtect(NULL,
126 RtlPrefetchMemoryNonTemporal,
127 Protect | PAGE_IS_WRITABLE);
128 *(PCHAR)RtlPrefetchMemoryNonTemporal = 0x90;
129 MmSetPageProtect(NULL, RtlPrefetchMemoryNonTemporal, Protect);
130 }
131 }
132
133 /* Check for, and enable SYSENTER support */
134 KiRestoreFastSyscallReturnState();
135
136 /* Loop every CPU */
137 i = KeActiveProcessors;
138 for (Affinity = 1; i; Affinity <<= 1)
139 {
140 /* Check if this is part of the set */
141 if (i & Affinity)
142 {
143 /* Run on this CPU */
144 i &= ~Affinity;
145 KeSetSystemAffinityThread(Affinity);
146
147 /* Reset MHz to 0 for this CPU */
148 KeGetCurrentPrcb()->MHz = 0;
149
150 /* Check if we can use RDTSC */
151 if (KeFeatureBits & KF_RDTSC)
152 {
153 /* Start sampling loop */
154 for (;;)
155 {
156 //
157 // FIXME: TODO
158 //
159 break;
160 }
161 }
162
163 /* Check if we have MTRR without PAT */
164 if (!(KeFeatureBits & KF_PAT) && (KeFeatureBits & KF_MTRR))
165 {
166 /* Then manually initialize MTRR for the CPU */
167 KiInitializeMTRR((BOOLEAN)i);
168 }
169
170 /* Check if we have AMD MTRR and initialize it for the CPU */
171 if (KeFeatureBits & KF_AMDK6MTRR) KiAmdK6InitializeMTRR();
172
173 /* Check if this is a buggy Pentium and apply the fixup if so */
174 if (KiI386PentiumLockErrataPresent) KiI386PentiumLockErrataFixup();
175
176 /* Get the current thread NPX state */
177 FxSaveArea = (PVOID)
178 ((ULONG_PTR)KeGetCurrentThread()->InitialStack -
179 NPX_FRAME_LENGTH);
180
181 /* Clear initial MXCsr mask */
182 FxSaveArea->U.FxArea.MXCsrMask = 0;
183
184 /* Save the current NPX State */
185 #ifdef __GNUC__
186 asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea));
187 #else
188 __asm fxsave [FxSaveArea]
189 #endif
190 /* Check if the current mask doesn't match the reserved bits */
191 if (FxSaveArea->U.FxArea.MXCsrMask != MXCsrMask)
192 {
193 /* Then use whatever it's holding */
194 MXCsrMask = FxSaveArea->U.FxArea.MXCsrMask;
195 }
196
197 /* Check if nobody set the kernel-wide mask */
198 if (!KiMXCsrMask)
199 {
200 /* Then use the one we calculated above */
201 NewMask = MXCsrMask;
202 }
203 else
204 {
205 /* Use the existing mask */
206 NewMask = KiMXCsrMask;
207
208 /* Was it set to the same value we found now? */
209 if (NewMask != MXCsrMask)
210 {
211 /* No, something is definitely wrong */
212 KEBUGCHECKEX(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED,
213 KF_FXSR,
214 NewMask,
215 MXCsrMask,
216 0);
217 }
218 }
219
220 /* Now set the kernel mask */
221 KiMXCsrMask = NewMask & MXCsrMask;
222 }
223 }
224
225 /* Return affinity back to where it was */
226 KeRevertToUserAffinityThread();
227
228 /* NT allows limiting the duration of an ISR with a registry key */
229 if (KiTimeLimitIsrMicroseconds)
230 {
231 /* FIXME: TODO */
232 DPRINT1("ISR Time Limit not yet supported\n");
233 }
234 }
235
236 VOID
237 NTAPI
238 KiInitializePcr(IN ULONG ProcessorNumber,
239 IN PKIPCR Pcr,
240 IN PKIDTENTRY Idt,
241 IN PKGDTENTRY Gdt,
242 IN PKTSS Tss,
243 IN PKTHREAD IdleThread,
244 IN PVOID DpcStack)
245 {
246 /* Setup the TIB */
247 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
248 Pcr->NtTib.StackBase = 0;
249 Pcr->NtTib.StackLimit = 0;
250 Pcr->NtTib.Self = 0;
251
252 /* Set the Current Thread */
253 Pcr->PrcbData.CurrentThread = IdleThread;
254
255 /* Set pointers to ourselves */
256 Pcr->Self = (PKPCR)Pcr;
257 Pcr->Prcb = &Pcr->PrcbData;
258
259 /* Set the PCR Version */
260 Pcr->MajorVersion = PCR_MAJOR_VERSION;
261 Pcr->MinorVersion = PCR_MINOR_VERSION;
262
263 /* Set the PCRB Version */
264 Pcr->PrcbData.MajorVersion = 1;
265 Pcr->PrcbData.MinorVersion = 1;
266
267 /* Set the Build Type */
268 Pcr->PrcbData.BuildType = 0;
269
270 /* Set the Processor Number and current Processor Mask */
271 Pcr->PrcbData.Number = (UCHAR)ProcessorNumber;
272 Pcr->PrcbData.SetMember = 1 << ProcessorNumber;
273
274 /* Set the PRCB for this Processor */
275 KiProcessorBlock[ProcessorNumber] = Pcr->Prcb;
276
277 /* Start us out at PASSIVE_LEVEL */
278 Pcr->Irql = PASSIVE_LEVEL;
279
280 /* Set the GDI, IDT, TSS and DPC Stack */
281 Pcr->GDT = (PVOID)Gdt;
282 Pcr->IDT = Idt;
283 Pcr->TSS = Tss;
284 Pcr->PrcbData.DpcStack = DpcStack;
285 }
286
287 VOID
288 NTAPI
289 KiInitializeKernel(IN PKPROCESS InitProcess,
290 IN PKTHREAD InitThread,
291 IN PVOID IdleStack,
292 IN PKPRCB Prcb,
293 IN CCHAR Number,
294 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
295 {
296 BOOLEAN NpxPresent;
297 ULONG FeatureBits;
298 LARGE_INTEGER PageDirectory;
299 PVOID DpcStack;
300
301 /* Detect and set the CPU Type */
302 KiSetProcessorType();
303
304 /* Set CR0 features based on detected CPU */
305 KiSetCR0Bits();
306
307 /* Check if an FPU is present */
308 NpxPresent = KiIsNpxPresent();
309
310 /* Initialize the Power Management Support for this PRCB */
311 PoInitializePrcb(Prcb);
312
313 /* Bugcheck if this is a 386 CPU */
314 if (Prcb->CpuType == 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
315
316 /* Get the processor features for the CPU */
317 FeatureBits = KiGetFeatureBits();
318
319 /* Save feature bits */
320 Prcb->FeatureBits = FeatureBits;
321
322 /* Set the default NX policy (opt-in) */
323 SharedUserData->NXSupportPolicy = 2;
324
325 /* Check if NPX is always on */
326 if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON"))
327 {
328 /* Set it always on */
329 SharedUserData->NXSupportPolicy = 1;
330 KeFeatureBits |= KF_NX_ENABLED;
331 }
332 else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT"))
333 {
334 /* Set it in opt-out mode */
335 SharedUserData->NXSupportPolicy = 3;
336 KeFeatureBits |= KF_NX_ENABLED;
337 }
338 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) ||
339 (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE")))
340 {
341 /* Set the feature bits */
342 KeFeatureBits |= KF_NX_ENABLED;
343 }
344 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) ||
345 (strstr(KeLoaderBlock->LoadOptions, "EXECUTE")))
346 {
347 /* Set disabled mode */
348 SharedUserData->NXSupportPolicy = 0;
349 KeFeatureBits |= KF_NX_DISABLED;
350 }
351
352 /* Save CPU state */
353 KiSaveProcessorControlState(&Prcb->ProcessorState);
354
355 /* Get cache line information for this CPU */
356 KiGetCacheInformation();
357
358 /* Initialize spinlocks and DPC data */
359 KiInitSpinLocks(Prcb, Number);
360
361 /* Check if this is the Boot CPU */
362 if (!Number)
363 {
364 /* Set Node Data */
365 KeNodeBlock[0] = &KiNode0;
366 Prcb->ParentNode = KeNodeBlock[0];
367 KeNodeBlock[0]->ProcessorMask = Prcb->SetMember;
368
369 /* Set boot-level flags */
370 KeI386NpxPresent = NpxPresent;
371 KeI386CpuType = Prcb->CpuType;
372 KeI386CpuStep = Prcb->CpuStep;
373 KeProcessorArchitecture = 0;
374 KeProcessorLevel = (USHORT)Prcb->CpuType;
375 if (Prcb->CpuID) KeProcessorRevision = Prcb->CpuStep;
376 KeFeatureBits = FeatureBits;
377 KeI386FxsrPresent = (KeFeatureBits & KF_FXSR) ? TRUE : FALSE;
378 KeI386XMMIPresent = (KeFeatureBits & KF_XMMI) ? TRUE : FALSE;
379
380 /* Set the current MP Master KPRCB to the Boot PRCB */
381 Prcb->MultiThreadSetMaster = Prcb;
382
383 /* Lower to APC_LEVEL */
384 KfLowerIrql(APC_LEVEL);
385
386 /* Initialize some spinlocks */
387 KeInitializeSpinLock(&KiFreezeExecutionLock);
388 KeInitializeSpinLock(&Ki486CompatibilityLock);
389
390 /* Initialize portable parts of the OS */
391 KiInitSystem();
392
393 /* Initialize the Idle Process and the Process Listhead */
394 InitializeListHead(&KiProcessListHead);
395 PageDirectory.QuadPart = 0;
396 KeInitializeProcess(InitProcess,
397 0,
398 0xFFFFFFFF,
399 &PageDirectory,
400 FALSE);
401 InitProcess->QuantumReset = MAXCHAR;
402 }
403 else
404 {
405 /* FIXME */
406 DPRINT1("SMP Boot support not yet present\n");
407 }
408
409 /* Initialize Kernel Memory Address Space */
410 MmInit1(FirstKrnlPhysAddr,
411 LastKrnlPhysAddr,
412 LastKernelAddress,
413 (PADDRESS_RANGE)&KeMemoryMap,
414 KeMemoryMapRangeCount,
415 4096);
416
417 /* Sets up the Text Sections of the Kernel and HAL for debugging */
418 LdrInit1();
419
420 /* Setup the Idle Thread */
421 KeInitializeThread(InitProcess,
422 InitThread,
423 NULL,
424 NULL,
425 NULL,
426 NULL,
427 NULL,
428 IdleStack);
429 InitThread->NextProcessor = Number;
430 InitThread->Priority = HIGH_PRIORITY;
431 InitThread->State = Running;
432 InitThread->Affinity = 1 << Number;
433 InitThread->WaitIrql = DISPATCH_LEVEL;
434 InitProcess->ActiveProcessors = 1 << Number;
435
436 /* HACK for MmUpdatePageDir */
437 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess;
438
439 /* Set up the thread-related fields in the PRCB */
440 Prcb->CurrentThread = InitThread;
441 Prcb->NextThread = NULL;
442 Prcb->IdleThread = InitThread;
443
444 /* Initialize the Kernel Executive */
445 ExpInitializeExecutive(Number, LoaderBlock);
446
447 /* Only do this on the boot CPU */
448 if (!Number)
449 {
450 /* Calculate the time reciprocal */
451 KiTimeIncrementReciprocal =
452 KiComputeReciprocal(KeMaximumIncrement,
453 &KiTimeIncrementShiftCount);
454
455 /* Update DPC Values in case they got updated by the executive */
456 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth;
457 Prcb->MinimumDpcRate = KiMinimumDpcRate;
458 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
459
460 /* Allocate the DPC Stack */
461 DpcStack = MmCreateKernelStack(FALSE);
462 if (!DpcStack) KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);
463 Prcb->DpcStack = DpcStack;
464
465 /* Allocate the IOPM save area. */
466 Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
467 PAGE_SIZE * 2,
468 TAG('K', 'e', ' ', ' '));
469 if (!Ki386IopmSaveArea)
470 {
471 /* Bugcheck. We need this for V86/VDM support. */
472 KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
473 }
474 }
475
476 /* Raise to Dispatch */
477 KfRaiseIrql(DISPATCH_LEVEL);
478
479 /* Set the Idle Priority to 0. This will jump into Phase 1 */
480 KeSetPriorityThread(InitThread, 0);
481
482 /* If there's no thread scheduled, put this CPU in the Idle summary */
483 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number;
484
485 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
486 KfRaiseIrql(HIGH_LEVEL);
487 LoaderBlock->Prcb = 0;
488 }
489
490 VOID
491 FASTCALL
492 KiGetMachineBootPointers(IN PKGDTENTRY *Gdt,
493 IN PKIDTENTRY *Idt,
494 IN PKIPCR *Pcr,
495 IN PKTSS *Tss)
496 {
497 KDESCRIPTOR GdtDescriptor, IdtDescriptor;
498 KGDTENTRY TssSelector, PcrSelector;
499 ULONG Tr, Fs;
500
501 /* Get GDT and IDT descriptors */
502 Ke386GetGlobalDescriptorTable(GdtDescriptor);
503 Ke386GetInterruptDescriptorTable(IdtDescriptor);
504
505 /* Save IDT and GDT */
506 *Gdt = (PKGDTENTRY)GdtDescriptor.Base;
507 *Idt = (PKIDTENTRY)IdtDescriptor.Base;
508
509 /* Get TSS and FS Selectors */
510 Ke386GetTr(&Tr);
511 if (Tr != KGDT_TSS) Tr = KGDT_TSS; // FIXME: HACKHACK
512 Fs = Ke386GetFs();
513
514 /* Get PCR Selector, mask it and get its GDT Entry */
515 PcrSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Fs & ~RPL_MASK));
516
517 /* Get the KPCR itself */
518 *Pcr = (PKIPCR)(ULONG_PTR)(PcrSelector.BaseLow |
519 PcrSelector.HighWord.Bytes.BaseMid << 16 |
520 PcrSelector.HighWord.Bytes.BaseHi << 24);
521
522 /* Get TSS Selector, mask it and get its GDT Entry */
523 TssSelector = *(PKGDTENTRY)((ULONG_PTR)*Gdt + (Tr & ~RPL_MASK));
524
525 /* Get the KTSS itself */
526 *Tss = (PKTSS)(ULONG_PTR)(TssSelector.BaseLow |
527 TssSelector.HighWord.Bytes.BaseMid << 16 |
528 TssSelector.HighWord.Bytes.BaseHi << 24);
529 }
530
531 VOID
532 NTAPI
533 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
534 {
535 ULONG Cpu;
536 PKTHREAD InitialThread;
537 ULONG InitialStack;
538 PKGDTENTRY Gdt;
539 PKIDTENTRY Idt;
540 PKTSS Tss;
541 PKIPCR Pcr;
542
543 /* Save the loader block and get the current CPU */
544 KeLoaderBlock = LoaderBlock;
545 Cpu = KeNumberProcessors;
546 if (!Cpu)
547 {
548 /* If this is the boot CPU, set FS and the CPU Number*/
549 Ke386SetFs(KGDT_R0_PCR);
550 __writefsdword(KPCR_PROCESSOR_NUMBER, Cpu);
551
552 /* Set the initial stack and idle thread as well */
553 LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack;
554 LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread;
555 }
556
557 /* Save the initial thread and stack */
558 InitialStack = LoaderBlock->KernelStack;
559 InitialThread = (PKTHREAD)LoaderBlock->Thread;
560
561 /* Clean the APC List Head */
562 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]);
563
564 /* Initialize the machine type */
565 KiInitializeMachineType();
566
567 /* Skip initial setup if this isn't the Boot CPU */
568 if (Cpu) goto AppCpuInit;
569
570 /* Get GDT, IDT, PCR and TSS pointers */
571 KiGetMachineBootPointers(&Gdt, &Idt, &Pcr, &Tss);
572
573 /* Setup the TSS descriptors and entries */
574 Ki386InitializeTss(Tss, Idt, Gdt);
575
576 /* Initialize the PCR */
577 RtlZeroMemory(Pcr, PAGE_SIZE);
578 KiInitializePcr(Cpu,
579 Pcr,
580 Idt,
581 Gdt,
582 Tss,
583 InitialThread,
584 KiDoubleFaultStack);
585
586 /* Set us as the current process */
587 InitialThread->ApcState.Process = &KiInitialProcess.Pcb;
588
589 /* Clear DR6/7 to cleanup bootloader debugging */
590 __writefsdword(KPCR_TEB, 0);
591 __writefsdword(KPCR_DR6, 0);
592 __writefsdword(KPCR_DR7, 0);
593
594 /* Load Ring 3 selectors for DS/ES */
595 Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
596 Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
597
598 AppCpuInit:
599 /* Loop until we can release the freeze lock */
600 do
601 {
602 /* Loop until execution can continue */
603 while ((volatile KSPIN_LOCK)KiFreezeExecutionLock == 1);
604 } while(InterlockedBitTestAndSet((PLONG)&KiFreezeExecutionLock, 0));
605
606 /* Setup CPU-related fields */
607 __writefsdword(KPCR_NUMBER, Cpu);
608 __writefsdword(KPCR_SET_MEMBER, 1 << Cpu);
609 __writefsdword(KPCR_SET_MEMBER_COPY, 1 << Cpu);
610 __writefsdword(KPCR_PRCB_SET_MEMBER, 1 << Cpu);
611
612 /* Initialize the Processor with HAL */
613 HalInitializeProcessor(Cpu, KeLoaderBlock);
614
615 /* Set active processors */
616 KeActiveProcessors |= __readfsdword(KPCR_SET_MEMBER);
617 KeNumberProcessors++;
618
619 /* Check if this is the boot CPU */
620 if (!Cpu)
621 {
622 /* Initialize debugging system */
623 KdInitSystem(0, KeLoaderBlock);
624
625 /* Check for break-in */
626 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
627 }
628
629 /* Raise to HIGH_LEVEL */
630 KfRaiseIrql(HIGH_LEVEL);
631
632 /* Align stack and make space for the trap frame and NPX frame */
633 InitialStack &= ~KTRAP_FRAME_ALIGN;
634 #ifdef __GNUC__
635 __asm__ __volatile__("movl %0,%%esp" : :"r" (InitialStack));
636 __asm__ __volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH +
637 KTRAP_FRAME_LENGTH +
638 KTRAP_FRAME_ALIGN));
639 __asm__ __volatile__("push %0" : :"r" (CR0_EM + CR0_TS + CR0_MP));
640 #else
641 __asm mov esp, InitialStack;
642 __asm sub esp, NPX_FRAME_LENGTH + KTRAP_FRAME_ALIGN + KTRAP_FRAME_LENGTH;
643 __asm push CR0_EM + CR0_TS + CR0_MP
644 #endif
645
646 /* Call main kernel initialization */
647 KiInitializeKernel(&KiInitialProcess.Pcb,
648 InitialThread,
649 (PVOID)InitialStack,
650 (PKPRCB)__readfsdword(KPCR_PRCB),
651 Cpu,
652 KeLoaderBlock);
653
654 /* Set the priority of this thread to 0 */
655 KeGetCurrentThread()->Priority = 0;
656
657 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
658 _enable();
659 KfLowerIrql(DISPATCH_LEVEL);
660
661 /* Set the right wait IRQL */
662 KeGetCurrentThread()->WaitIrql = DISPATCH_LEVEL;
663
664 /* Set idle thread as running on UP builds */
665 #ifndef CONFIG_SMP
666 KeGetCurrentThread()->State = Running;
667 #endif
668
669 /* Jump into the idle loop */
670 KiIdleLoop();
671 }
672