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)
9 /* INCLUDES *****************************************************************/
14 #include "internal/trap_x.h"
16 /* GLOBALS *******************************************************************/
18 /* Boot and double-fault/NMI/DPC stack */
19 UCHAR P0BootStackData
[KERNEL_STACK_SIZE
] __attribute__((aligned (16))) = {0};
20 UCHAR KiDoubleFaultStackData
[KERNEL_STACK_SIZE
] __attribute__((aligned (16))) = {0};
21 ULONG_PTR P0BootStack
= (ULONG_PTR
)&P0BootStackData
[KERNEL_STACK_SIZE
];
22 ULONG_PTR KiDoubleFaultStack
= (ULONG_PTR
)&KiDoubleFaultStackData
[KERNEL_STACK_SIZE
];
24 /* Spinlocks used only on X86 */
25 KSPIN_LOCK KiFreezeExecutionLock
;
26 KSPIN_LOCK Ki486CompatibilityLock
;
30 ULONGLONG BootCycles
, BootCyclesEnd
;
32 /* FUNCTIONS *****************************************************************/
36 KiInitMachineDependent(VOID
)
39 BOOLEAN FbCaching
= FALSE
;
42 ULONG i
, Affinity
, Sample
= 0;
43 PFX_SAVE_AREA FxSaveArea
;
44 ULONG MXCsrMask
= 0xFFBF;
46 KI_SAMPLE_MAP Samples
[4];
47 PKI_SAMPLE_MAP CurrentSample
= Samples
;
49 /* Check for large page support */
50 if (KeFeatureBits
& KF_LARGE_PAGE
)
52 /* FIXME: Support this */
53 DPRINT1("Large Page support detected but not yet taken advantage of\n");
56 /* Check for global page support */
57 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
59 /* Do an IPI to enable it on all CPUs */
60 CpuCount
= KeNumberProcessors
;
61 KeIpiGenericCall(Ki386EnableGlobalPage
, (ULONG_PTR
)&CpuCount
);
64 /* Check for PAT and/or MTRR support */
65 if (KeFeatureBits
& (KF_PAT
| KF_MTRR
))
67 /* Query the HAL to make sure we can use it */
68 Status
= HalQuerySystemInformation(HalFrameBufferCachingInformation
,
72 if ((NT_SUCCESS(Status
)) && (FbCaching
))
74 /* We can't, disable it */
75 KeFeatureBits
&= ~(KF_PAT
| KF_MTRR
);
79 /* Check for PAT support and enable it */
80 if (KeFeatureBits
& KF_PAT
) KiInitializePAT();
82 /* Assume no errata for now */
83 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = 0;
85 /* Check if we have an NPX */
89 i
= KeActiveProcessors
;
90 for (Affinity
= 1; i
; Affinity
<<= 1)
92 /* Check if this is part of the set */
97 KeSetSystemAffinityThread(Affinity
);
99 /* Detect FPU errata */
100 if (KiIsNpxErrataPresent())
102 /* Disable NPX support */
103 KeI386NpxPresent
= FALSE
;
105 ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] =
113 /* If there's no NPX, then we're emulating the FPU */
114 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] =
117 /* Check if there's no NPX, so that we can disable associated features */
118 if (!KeI386NpxPresent
)
120 /* Remove NPX-related bits */
121 KeFeatureBits
&= ~(KF_XMMI64
| KF_XMMI
| KF_FXSR
| KF_MMX
);
123 /* Disable kernel flags */
124 KeI386FxsrPresent
= KeI386XMMIPresent
= FALSE
;
126 /* Disable processor features that might've been set until now */
127 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] =
128 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
129 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
130 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
131 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] = 0;
134 /* Check for CR4 support */
135 if (KeFeatureBits
& KF_CR4
)
137 /* Do an IPI call to enable the Debug Exceptions */
138 CpuCount
= KeNumberProcessors
;
139 KeIpiGenericCall(Ki386EnableDE
, (ULONG_PTR
)&CpuCount
);
142 /* Check if FXSR was found */
143 if (KeFeatureBits
& KF_FXSR
)
145 /* Do an IPI call to enable the FXSR */
146 CpuCount
= KeNumberProcessors
;
147 KeIpiGenericCall(Ki386EnableFxsr
, (ULONG_PTR
)&CpuCount
);
149 /* Check if XMM was found too */
150 if (KeFeatureBits
& KF_XMMI
)
152 /* Do an IPI call to enable XMMI exceptions */
153 CpuCount
= KeNumberProcessors
;
154 KeIpiGenericCall(Ki386EnableXMMIExceptions
, (ULONG_PTR
)&CpuCount
);
156 /* FIXME: Implement and enable XMM Page Zeroing for Mm */
158 /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */
159 *(PCHAR
)RtlPrefetchMemoryNonTemporal
= 0x90;
163 /* Check for, and enable SYSENTER support */
164 KiRestoreFastSyscallReturnState();
167 i
= KeActiveProcessors
;
168 for (Affinity
= 1; i
; Affinity
<<= 1)
170 /* Check if this is part of the set */
173 /* Run on this CPU */
175 KeSetSystemAffinityThread(Affinity
);
177 /* Reset MHz to 0 for this CPU */
178 KeGetCurrentPrcb()->MHz
= 0;
180 /* Check if we can use RDTSC */
181 if (KeFeatureBits
& KF_RDTSC
)
183 /* Start sampling loop */
186 /* Do a dummy CPUID to start the sample */
187 CPUID(0, &Dummy
, &Dummy
, &Dummy
, &Dummy
);
189 /* Fill out the starting data */
190 CurrentSample
->PerfStart
= KeQueryPerformanceCounter(NULL
);
191 CurrentSample
->TSCStart
= __rdtsc();
192 CurrentSample
->PerfFreq
.QuadPart
= -50000;
194 /* Sleep for this sample */
195 KeDelayExecutionThread(KernelMode
,
197 &CurrentSample
->PerfFreq
);
199 /* Do another dummy CPUID */
200 CPUID(0, &Dummy
, &Dummy
, &Dummy
, &Dummy
);
202 /* Fill out the ending data */
203 CurrentSample
->PerfEnd
=
204 KeQueryPerformanceCounter(&CurrentSample
->PerfFreq
);
205 CurrentSample
->TSCEnd
= __rdtsc();
207 /* Calculate the differences */
208 CurrentSample
->PerfDelta
= CurrentSample
->PerfEnd
.QuadPart
-
209 CurrentSample
->PerfStart
.QuadPart
;
210 CurrentSample
->TSCDelta
= CurrentSample
->TSCEnd
-
211 CurrentSample
->TSCStart
;
213 /* Compute CPU Speed */
214 CurrentSample
->MHz
= (ULONG
)((CurrentSample
->TSCDelta
*
216 PerfFreq
.QuadPart
+ 500000) /
217 (CurrentSample
->PerfDelta
*
220 /* Check if this isn't the first sample */
223 /* Check if we got a good precision within 1MHz */
224 if ((CurrentSample
->MHz
== CurrentSample
[-1].MHz
) ||
225 (CurrentSample
->MHz
== CurrentSample
[-1].MHz
+ 1) ||
226 (CurrentSample
->MHz
== CurrentSample
[-1].MHz
- 1))
228 /* We did, stop sampling */
237 if (Sample
== sizeof(Samples
) / sizeof(Samples
[0]))
240 CurrentSample
= Samples
;
245 /* Save the CPU Speed */
246 KeGetCurrentPrcb()->MHz
= CurrentSample
[-1].MHz
;
249 /* Check if we have MTRR */
250 if (KeFeatureBits
& KF_MTRR
)
252 /* Then manually initialize MTRR for the CPU */
253 KiInitializeMTRR(i
? FALSE
: TRUE
);
256 /* Check if we have AMD MTRR and initialize it for the CPU */
257 if (KeFeatureBits
& KF_AMDK6MTRR
) KiAmdK6InitializeMTRR();
259 /* Check if this is a buggy Pentium and apply the fixup if so */
260 if (KiI386PentiumLockErrataPresent
) KiI386PentiumLockErrataFixup();
262 /* Check if the CPU supports FXSR */
263 if (KeFeatureBits
& KF_FXSR
)
265 /* Get the current thread NPX state */
267 ((ULONG_PTR
)KeGetCurrentThread()->InitialStack
-
270 /* Clear initial MXCsr mask */
271 FxSaveArea
->U
.FxArea
.MXCsrMask
= 0;
273 /* Save the current NPX State */
275 asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea
));
277 __asm fxsave
[FxSaveArea
]
279 /* Check if the current mask doesn't match the reserved bits */
280 if (FxSaveArea
->U
.FxArea
.MXCsrMask
!= 0)
282 /* Then use whatever it's holding */
283 MXCsrMask
= FxSaveArea
->U
.FxArea
.MXCsrMask
;
286 /* Check if nobody set the kernel-wide mask */
289 /* Then use the one we calculated above */
290 KiMXCsrMask
= MXCsrMask
;
294 /* Was it set to the same value we found now? */
295 if (KiMXCsrMask
!= MXCsrMask
)
297 /* No, something is definitely wrong */
298 KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED
,
306 /* Now set the kernel mask */
307 KiMXCsrMask
&= MXCsrMask
;
312 /* Return affinity back to where it was */
313 KeRevertToUserAffinityThread();
315 /* NT allows limiting the duration of an ISR with a registry key */
316 if (KiTimeLimitIsrMicroseconds
)
319 DPRINT1("ISR Time Limit not yet supported\n");
322 /* Set CR0 features based on detected CPU */
328 KiInitializePcr(IN ULONG ProcessorNumber
,
333 IN PKTHREAD IdleThread
,
337 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
338 Pcr
->NtTib
.StackBase
= 0;
339 Pcr
->NtTib
.StackLimit
= 0;
340 Pcr
->NtTib
.Self
= NULL
;
342 /* Set the Current Thread */
343 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
345 /* Set pointers to ourselves */
346 Pcr
->Self
= (PKPCR
)Pcr
;
347 Pcr
->Prcb
= &Pcr
->PrcbData
;
349 /* Set the PCR Version */
350 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
351 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
353 /* Set the PCRB Version */
354 Pcr
->PrcbData
.MajorVersion
= 1;
355 Pcr
->PrcbData
.MinorVersion
= 1;
357 /* Set the Build Type */
358 Pcr
->PrcbData
.BuildType
= 0;
360 Pcr
->PrcbData
.BuildType
|= PRCB_BUILD_UNIPROCESSOR
;
363 Pcr
->PrcbData
.BuildType
|= PRCB_BUILD_DEBUG
;
366 /* Set the Processor Number and current Processor Mask */
367 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
368 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
370 /* Set the PRCB for this Processor */
371 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
373 /* Start us out at PASSIVE_LEVEL */
374 Pcr
->Irql
= PASSIVE_LEVEL
;
376 /* Set the GDI, IDT, TSS and DPC Stack */
377 Pcr
->GDT
= (PVOID
)Gdt
;
381 Pcr
->PrcbData
.DpcStack
= DpcStack
;
383 /* Setup the processor set */
384 Pcr
->PrcbData
.MultiThreadProcessorSet
= Pcr
->PrcbData
.SetMember
;
389 KiInitializeKernel(IN PKPROCESS InitProcess
,
390 IN PKTHREAD InitThread
,
394 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
398 ULONG PageDirectory
[2];
402 /* Detect and set the CPU Type */
403 KiSetProcessorType();
405 /* Check if an FPU is present */
406 NpxPresent
= KiIsNpxPresent();
408 /* Initialize the Power Management Support for this PRCB */
409 PoInitializePrcb(Prcb
);
411 /* Bugcheck if this is a 386 CPU */
412 if (Prcb
->CpuType
== 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
414 /* Get the processor features for the CPU */
415 FeatureBits
= KiGetFeatureBits();
417 /* Set the default NX policy (opt-in) */
418 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTIN
;
420 /* Check if NPX is always on */
421 if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSON"))
423 /* Set it always on */
424 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSON
;
425 FeatureBits
|= KF_NX_ENABLED
;
427 else if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTOUT"))
429 /* Set it in opt-out mode */
430 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTOUT
;
431 FeatureBits
|= KF_NX_ENABLED
;
433 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTIN")) ||
434 (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE")))
436 /* Set the feature bits */
437 FeatureBits
|= KF_NX_ENABLED
;
439 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSOFF")) ||
440 (strstr(KeLoaderBlock
->LoadOptions
, "EXECUTE")))
442 /* Set disabled mode */
443 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSOFF
;
444 FeatureBits
|= KF_NX_DISABLED
;
447 /* Save feature bits */
448 Prcb
->FeatureBits
= FeatureBits
;
451 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
453 /* Get cache line information for this CPU */
454 KiGetCacheInformation();
456 /* Initialize spinlocks and DPC data */
457 KiInitSpinLocks(Prcb
, Number
);
459 /* Check if this is the Boot CPU */
463 KeNodeBlock
[0] = &KiNode0
;
464 Prcb
->ParentNode
= KeNodeBlock
[0];
465 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
467 /* Set boot-level flags */
468 KeI386NpxPresent
= NpxPresent
;
469 KeI386CpuType
= Prcb
->CpuType
;
470 KeI386CpuStep
= Prcb
->CpuStep
;
471 KeProcessorArchitecture
= PROCESSOR_ARCHITECTURE_INTEL
;
472 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
473 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
474 KeFeatureBits
= FeatureBits
;
475 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
476 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
478 /* Detect 8-byte compare exchange support */
479 if (!(KeFeatureBits
& KF_CMPXCHG8B
))
481 /* Copy the vendor string */
482 RtlCopyMemory(Vendor
, Prcb
->VendorString
, sizeof(Vendor
));
484 /* Bugcheck the system. Windows *requires* this */
486 (1 << 24 ) | (Prcb
->CpuType
<< 16) | Prcb
->CpuStep
,
492 /* Set the current MP Master KPRCB to the Boot PRCB */
493 Prcb
->MultiThreadSetMaster
= Prcb
;
495 /* Lower to APC_LEVEL */
496 KeLowerIrql(APC_LEVEL
);
498 /* Initialize some spinlocks */
499 KeInitializeSpinLock(&KiFreezeExecutionLock
);
500 KeInitializeSpinLock(&Ki486CompatibilityLock
);
502 /* Initialize portable parts of the OS */
505 /* Initialize the Idle Process and the Process Listhead */
506 InitializeListHead(&KiProcessListHead
);
507 PageDirectory
[0] = 0;
508 PageDirectory
[1] = 0;
509 KeInitializeProcess(InitProcess
,
514 InitProcess
->QuantumReset
= MAXCHAR
;
519 DPRINT1("SMP Boot support not yet present\n");
522 /* Setup the Idle Thread */
523 KeInitializeThread(InitProcess
,
531 InitThread
->NextProcessor
= Number
;
532 InitThread
->Priority
= HIGH_PRIORITY
;
533 InitThread
->State
= Running
;
534 InitThread
->Affinity
= 1 << Number
;
535 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
536 InitProcess
->ActiveProcessors
= 1 << Number
;
538 /* HACK for MmUpdatePageDir */
539 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
541 /* Set basic CPU Features that user mode can read */
542 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
543 (KeFeatureBits
& KF_MMX
) ? TRUE
: FALSE
;
544 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
545 (KeFeatureBits
& KF_CMPXCHG8B
) ? TRUE
: FALSE
;
546 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
547 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI
)) ? TRUE
: FALSE
;
548 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
549 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI64
)) ? TRUE
: FALSE
;
550 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
551 (KeFeatureBits
& KF_3DNOW
) ? TRUE
: FALSE
;
552 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
553 (KeFeatureBits
& KF_RDTSC
) ? TRUE
: FALSE
;
555 /* Set up the thread-related fields in the PRCB */
556 Prcb
->CurrentThread
= InitThread
;
557 Prcb
->NextThread
= NULL
;
558 Prcb
->IdleThread
= InitThread
;
560 /* Initialize the Kernel Executive */
561 ExpInitializeExecutive(Number
, LoaderBlock
);
563 /* Only do this on the boot CPU */
566 /* Calculate the time reciprocal */
567 KiTimeIncrementReciprocal
=
568 KiComputeReciprocal(KeMaximumIncrement
,
569 &KiTimeIncrementShiftCount
);
571 /* Update DPC Values in case they got updated by the executive */
572 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
573 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
574 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
576 /* Allocate the DPC Stack */
577 DpcStack
= MmCreateKernelStack(FALSE
, 0);
578 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
579 Prcb
->DpcStack
= DpcStack
;
581 /* Allocate the IOPM save area. */
582 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
585 if (!Ki386IopmSaveArea
)
587 /* Bugcheck. We need this for V86/VDM support. */
588 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
592 /* Raise to Dispatch */
593 KfRaiseIrql(DISPATCH_LEVEL
);
595 /* Set the Idle Priority to 0. This will jump into Phase 1 */
596 KeSetPriorityThread(InitThread
, 0);
598 /* If there's no thread scheduled, put this CPU in the Idle summary */
599 KiAcquirePrcbLock(Prcb
);
600 if (!Prcb
->NextThread
) KiIdleSummary
|= 1 << Number
;
601 KiReleasePrcbLock(Prcb
);
603 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
604 KfRaiseIrql(HIGH_LEVEL
);
605 LoaderBlock
->Prcb
= 0;
610 KiGetMachineBootPointers(IN PKGDTENTRY
*Gdt
,
615 KDESCRIPTOR GdtDescriptor
, IdtDescriptor
;
616 KGDTENTRY TssSelector
, PcrSelector
;
619 /* Get GDT and IDT descriptors */
620 Ke386GetGlobalDescriptorTable(&GdtDescriptor
.Limit
);
621 __sidt(&IdtDescriptor
.Limit
);
623 /* Save IDT and GDT */
624 *Gdt
= (PKGDTENTRY
)GdtDescriptor
.Base
;
625 *Idt
= (PKIDTENTRY
)IdtDescriptor
.Base
;
627 /* Get TSS and FS Selectors */
631 /* Get PCR Selector, mask it and get its GDT Entry */
632 PcrSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Fs
& ~RPL_MASK
));
634 /* Get the KPCR itself */
635 *Pcr
= (PKIPCR
)(ULONG_PTR
)(PcrSelector
.BaseLow
|
636 PcrSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
637 PcrSelector
.HighWord
.Bytes
.BaseHi
<< 24);
639 /* Get TSS Selector, mask it and get its GDT Entry */
640 TssSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Tr
& ~RPL_MASK
));
642 /* Get the KTSS itself */
643 *Tss
= (PKTSS
)(ULONG_PTR
)(TssSelector
.BaseLow
|
644 TssSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
645 TssSelector
.HighWord
.Bytes
.BaseHi
<< 24);
650 KiSystemStartupBootStack(VOID
)
654 /* Initialize the kernel for the current CPU */
655 KiInitializeKernel(&KiInitialProcess
.Pcb
,
656 (PKTHREAD
)KeLoaderBlock
->Thread
,
657 (PVOID
)(KeLoaderBlock
->KernelStack
& ~3),
658 (PKPRCB
)__readfsdword(KPCR_PRCB
),
659 KeNumberProcessors
- 1,
662 /* Set the priority of this thread to 0 */
663 Thread
= KeGetCurrentThread();
664 Thread
->Priority
= 0;
666 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
668 KfLowerIrql(DISPATCH_LEVEL
);
670 /* Set the right wait IRQL */
671 Thread
->WaitIrql
= DISPATCH_LEVEL
;
673 /* Jump into the idle loop */
679 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
682 PKTHREAD InitialThread
;
686 KIDTENTRY NmiEntry
, DoubleFaultEntry
;
690 /* Boot cycles timestamp */
691 BootCycles
= __rdtsc();
693 /* Check if we are being booted from FreeLDR */
694 if (!((ULONG_PTR
)LoaderBlock
& 0x80000000)) KiRosPrepareForSystemStartup((PROS_LOADER_PARAMETER_BLOCK
)LoaderBlock
);
696 /* Save the loader block and get the current CPU */
697 KeLoaderBlock
= LoaderBlock
;
698 Cpu
= KeNumberProcessors
;
701 /* If this is the boot CPU, set FS and the CPU Number*/
702 Ke386SetFs(KGDT_R0_PCR
);
703 __writefsdword(KPCR_PROCESSOR_NUMBER
, Cpu
);
705 /* Set the initial stack and idle thread as well */
706 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
707 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
710 /* Save the initial thread and stack */
711 InitialStack
= LoaderBlock
->KernelStack
;
712 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
714 /* Clean the APC List Head */
715 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
717 /* Initialize the machine type */
718 KiInitializeMachineType();
720 /* Skip initial setup if this isn't the Boot CPU */
721 if (Cpu
) goto AppCpuInit
;
723 /* Get GDT, IDT, PCR and TSS pointers */
724 KiGetMachineBootPointers(&Gdt
, &Idt
, &Pcr
, &Tss
);
726 /* Setup the TSS descriptors and entries */
727 Ki386InitializeTss(Tss
, Idt
, Gdt
);
729 /* Initialize the PCR */
730 RtlZeroMemory(Pcr
, PAGE_SIZE
);
737 (PVOID
)KiDoubleFaultStack
);
739 /* Set us as the current process */
740 InitialThread
->ApcState
.Process
= &KiInitialProcess
.Pcb
;
742 /* Clear DR6/7 to cleanup bootloader debugging */
743 __writefsdword(KPCR_TEB
, 0);
744 __writefsdword(KPCR_DR6
, 0);
745 __writefsdword(KPCR_DR7
, 0);
750 /* Load Ring 3 selectors for DS/ES */
751 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
752 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
754 /* Save NMI and double fault traps */
755 RtlCopyMemory(&NmiEntry
, &Idt
[2], sizeof(KIDTENTRY
));
756 RtlCopyMemory(&DoubleFaultEntry
, &Idt
[8], sizeof(KIDTENTRY
));
758 /* Copy kernel's trap handlers */
760 (PVOID
)KiIdtDescriptor
.Base
,
761 KiIdtDescriptor
.Limit
+ 1);
763 /* Restore NMI and double fault */
764 RtlCopyMemory(&Idt
[2], &NmiEntry
, sizeof(KIDTENTRY
));
765 RtlCopyMemory(&Idt
[8], &DoubleFaultEntry
, sizeof(KIDTENTRY
));
768 /* Loop until we can release the freeze lock */
771 /* Loop until execution can continue */
772 while (*(volatile PKSPIN_LOCK
*)&KiFreezeExecutionLock
== (PVOID
)1);
773 } while(InterlockedBitTestAndSet((PLONG
)&KiFreezeExecutionLock
, 0));
775 /* Setup CPU-related fields */
776 __writefsdword(KPCR_NUMBER
, Cpu
);
777 __writefsdword(KPCR_SET_MEMBER
, 1 << Cpu
);
778 __writefsdword(KPCR_SET_MEMBER_COPY
, 1 << Cpu
);
779 __writefsdword(KPCR_PRCB_SET_MEMBER
, 1 << Cpu
);
781 /* Initialize the Processor with HAL */
782 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
784 /* Set active processors */
785 KeActiveProcessors
|= __readfsdword(KPCR_SET_MEMBER
);
786 KeNumberProcessors
++;
788 /* Check if this is the boot CPU */
791 /* Initialize debugging system */
792 KdInitSystem(0, KeLoaderBlock
);
794 /* Check for break-in */
795 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
798 /* Raise to HIGH_LEVEL */
799 KfRaiseIrql(HIGH_LEVEL
);
801 /* Switch to new kernel stack and start kernel bootstrapping */
802 KiSwitchToBootStack(InitialStack
& ~3);