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/i386/trap_x.h"
16 /* GLOBALS *******************************************************************/
18 /* Boot and double-fault/NMI/DPC stack */
19 UCHAR
DECLSPEC_ALIGN(PAGE_SIZE
) P0BootStackData
[KERNEL_STACK_SIZE
] = {0};
20 UCHAR
DECLSPEC_ALIGN(PAGE_SIZE
) KiDoubleFaultStackData
[KERNEL_STACK_SIZE
] = {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 *****************************************************************/
37 KiInitMachineDependent(VOID
)
40 BOOLEAN FbCaching
= FALSE
;
43 ULONG i
, Affinity
, Sample
= 0;
44 PFX_SAVE_AREA FxSaveArea
;
45 ULONG MXCsrMask
= 0xFFBF;
47 KI_SAMPLE_MAP Samples
[10];
48 PKI_SAMPLE_MAP CurrentSample
= Samples
;
49 LARGE_IDENTITY_MAP IdentityMap
;
51 /* Check for large page support */
52 if (KeFeatureBits
& KF_LARGE_PAGE
)
54 /* Do an IPI to enable it on all CPUs */
55 if (Ki386CreateIdentityMap(&IdentityMap
, Ki386EnableCurrentLargePage
, 2))
56 KeIpiGenericCall(Ki386EnableTargetLargePage
, (ULONG_PTR
)&IdentityMap
);
58 /* Free the pages allocated for identity map */
59 Ki386FreeIdentityMap(&IdentityMap
);
62 /* Check for global page support */
63 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
65 /* Do an IPI to enable it on all CPUs */
66 CpuCount
= KeNumberProcessors
;
67 KeIpiGenericCall(Ki386EnableGlobalPage
, (ULONG_PTR
)&CpuCount
);
70 /* Check for PAT and/or MTRR support */
71 if (KeFeatureBits
& (KF_PAT
| KF_MTRR
))
73 /* Query the HAL to make sure we can use it */
74 Status
= HalQuerySystemInformation(HalFrameBufferCachingInformation
,
78 if ((NT_SUCCESS(Status
)) && (FbCaching
))
80 /* We can't, disable it */
81 KeFeatureBits
&= ~(KF_PAT
| KF_MTRR
);
85 /* Check for PAT support and enable it */
86 if (KeFeatureBits
& KF_PAT
) KiInitializePAT();
88 /* Assume no errata for now */
89 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = 0;
91 /* Check if we have an NPX */
95 i
= KeActiveProcessors
;
96 for (Affinity
= 1; i
; Affinity
<<= 1)
98 /* Check if this is part of the set */
101 /* Run on this CPU */
103 KeSetSystemAffinityThread(Affinity
);
105 /* Detect FPU errata */
106 if (KiIsNpxErrataPresent())
108 /* Disable NPX support */
109 KeI386NpxPresent
= FALSE
;
111 ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] =
119 /* If there's no NPX, then we're emulating the FPU */
120 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] =
123 /* Check if there's no NPX, so that we can disable associated features */
124 if (!KeI386NpxPresent
)
126 /* Remove NPX-related bits */
127 KeFeatureBits
&= ~(KF_XMMI64
| KF_XMMI
| KF_FXSR
| KF_MMX
);
129 /* Disable kernel flags */
130 KeI386FxsrPresent
= KeI386XMMIPresent
= FALSE
;
132 /* Disable processor features that might've been set until now */
133 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] =
134 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
135 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
136 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
137 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] = 0;
140 /* Check for CR4 support */
141 if (KeFeatureBits
& KF_CR4
)
143 /* Do an IPI call to enable the Debug Exceptions */
144 CpuCount
= KeNumberProcessors
;
145 KeIpiGenericCall(Ki386EnableDE
, (ULONG_PTR
)&CpuCount
);
148 /* Check if FXSR was found */
149 if (KeFeatureBits
& KF_FXSR
)
151 /* Do an IPI call to enable the FXSR */
152 CpuCount
= KeNumberProcessors
;
153 KeIpiGenericCall(Ki386EnableFxsr
, (ULONG_PTR
)&CpuCount
);
155 /* Check if XMM was found too */
156 if (KeFeatureBits
& KF_XMMI
)
158 /* Do an IPI call to enable XMMI exceptions */
159 CpuCount
= KeNumberProcessors
;
160 KeIpiGenericCall(Ki386EnableXMMIExceptions
, (ULONG_PTR
)&CpuCount
);
162 /* FIXME: Implement and enable XMM Page Zeroing for Mm */
164 /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */
165 *(PCHAR
)RtlPrefetchMemoryNonTemporal
= 0x90; // NOP
169 /* Check for, and enable SYSENTER support */
170 KiRestoreFastSyscallReturnState();
173 i
= KeActiveProcessors
;
174 for (Affinity
= 1; i
; Affinity
<<= 1)
176 /* Check if this is part of the set */
179 /* Run on this CPU */
181 KeSetSystemAffinityThread(Affinity
);
183 /* Reset MHz to 0 for this CPU */
184 KeGetCurrentPrcb()->MHz
= 0;
186 /* Check if we can use RDTSC */
187 if (KeFeatureBits
& KF_RDTSC
)
189 /* Start sampling loop */
192 /* Do a dummy CPUID to start the sample */
193 KiCpuId(&CpuInfo
, 0);
195 /* Fill out the starting data */
196 CurrentSample
->PerfStart
= KeQueryPerformanceCounter(NULL
);
197 CurrentSample
->TSCStart
= __rdtsc();
198 CurrentSample
->PerfFreq
.QuadPart
= -50000;
200 /* Sleep for this sample */
201 KeDelayExecutionThread(KernelMode
,
203 &CurrentSample
->PerfFreq
);
205 /* Do another dummy CPUID */
206 KiCpuId(&CpuInfo
, 0);
208 /* Fill out the ending data */
209 CurrentSample
->PerfEnd
=
210 KeQueryPerformanceCounter(&CurrentSample
->PerfFreq
);
211 CurrentSample
->TSCEnd
= __rdtsc();
213 /* Calculate the differences */
214 CurrentSample
->PerfDelta
= CurrentSample
->PerfEnd
.QuadPart
-
215 CurrentSample
->PerfStart
.QuadPart
;
216 CurrentSample
->TSCDelta
= CurrentSample
->TSCEnd
-
217 CurrentSample
->TSCStart
;
219 /* Compute CPU Speed */
220 CurrentSample
->MHz
= (ULONG
)((CurrentSample
->TSCDelta
*
222 PerfFreq
.QuadPart
+ 500000) /
223 (CurrentSample
->PerfDelta
*
226 /* Check if this isn't the first sample */
229 /* Check if we got a good precision within 1MHz */
230 if ((CurrentSample
->MHz
== CurrentSample
[-1].MHz
) ||
231 (CurrentSample
->MHz
== CurrentSample
[-1].MHz
+ 1) ||
232 (CurrentSample
->MHz
== CurrentSample
[-1].MHz
- 1))
234 /* We did, stop sampling */
243 if (Sample
== RTL_NUMBER_OF(Samples
))
245 /* No luck. Average the samples and be done */
249 TotalMHz
+= Samples
[Sample
].MHz
;
251 CurrentSample
[-1].MHz
= TotalMHz
/ RTL_NUMBER_OF(Samples
);
252 DPRINT1("Sampling CPU frequency failed. Using average of %lu MHz\n", CurrentSample
[-1].MHz
);
257 /* Save the CPU Speed */
258 KeGetCurrentPrcb()->MHz
= CurrentSample
[-1].MHz
;
261 /* Check if we have MTRR */
262 if (KeFeatureBits
& KF_MTRR
)
264 /* Then manually initialize MTRR for the CPU */
265 KiInitializeMTRR(i
? FALSE
: TRUE
);
268 /* Check if we have AMD MTRR and initialize it for the CPU */
269 if (KeFeatureBits
& KF_AMDK6MTRR
) KiAmdK6InitializeMTRR();
271 /* Check if this is a buggy Pentium and apply the fixup if so */
272 if (KiI386PentiumLockErrataPresent
) KiI386PentiumLockErrataFixup();
274 /* Check if the CPU supports FXSR */
275 if (KeFeatureBits
& KF_FXSR
)
277 /* Get the current thread NPX state */
278 FxSaveArea
= KiGetThreadNpxArea(KeGetCurrentThread());
280 /* Clear initial MXCsr mask */
281 FxSaveArea
->U
.FxArea
.MXCsrMask
= 0;
283 /* Save the current NPX State */
284 Ke386SaveFpuState(FxSaveArea
);
286 /* Check if the current mask doesn't match the reserved bits */
287 if (FxSaveArea
->U
.FxArea
.MXCsrMask
!= 0)
289 /* Then use whatever it's holding */
290 MXCsrMask
= FxSaveArea
->U
.FxArea
.MXCsrMask
;
293 /* Check if nobody set the kernel-wide mask */
296 /* Then use the one we calculated above */
297 KiMXCsrMask
= MXCsrMask
;
301 /* Was it set to the same value we found now? */
302 if (KiMXCsrMask
!= MXCsrMask
)
304 /* No, something is definitely wrong */
305 KeBugCheckEx(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED
,
313 /* Now set the kernel mask */
314 KiMXCsrMask
&= MXCsrMask
;
319 /* Return affinity back to where it was */
320 KeRevertToUserAffinityThread();
322 /* NT allows limiting the duration of an ISR with a registry key */
323 if (KiTimeLimitIsrMicroseconds
)
326 DPRINT1("ISR Time Limit not yet supported\n");
329 /* Set CR0 features based on detected CPU */
336 KiInitializePcr(IN ULONG ProcessorNumber
,
341 IN PKTHREAD IdleThread
,
345 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
346 Pcr
->NtTib
.StackBase
= 0;
347 Pcr
->NtTib
.StackLimit
= 0;
348 Pcr
->NtTib
.Self
= NULL
;
350 /* Set the Current Thread */
351 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
353 /* Set pointers to ourselves */
354 Pcr
->SelfPcr
= (PKPCR
)Pcr
;
355 Pcr
->Prcb
= &Pcr
->PrcbData
;
357 /* Set the PCR Version */
358 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
359 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
361 /* Set the PCRB Version */
362 Pcr
->PrcbData
.MajorVersion
= 1;
363 Pcr
->PrcbData
.MinorVersion
= 1;
365 /* Set the Build Type */
366 Pcr
->PrcbData
.BuildType
= 0;
368 Pcr
->PrcbData
.BuildType
|= PRCB_BUILD_UNIPROCESSOR
;
371 Pcr
->PrcbData
.BuildType
|= PRCB_BUILD_DEBUG
;
374 /* Set the Processor Number and current Processor Mask */
375 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
376 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
378 /* Set the PRCB for this Processor */
379 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
381 /* Start us out at PASSIVE_LEVEL */
382 Pcr
->Irql
= PASSIVE_LEVEL
;
384 /* Set the GDI, IDT, TSS and DPC Stack */
385 Pcr
->GDT
= (PVOID
)Gdt
;
389 Pcr
->PrcbData
.DpcStack
= DpcStack
;
391 /* Setup the processor set */
392 Pcr
->PrcbData
.MultiThreadProcessorSet
= Pcr
->PrcbData
.SetMember
;
398 KiInitializeKernel(IN PKPROCESS InitProcess
,
399 IN PKTHREAD InitThread
,
403 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
407 ULONG PageDirectory
[2];
412 /* Detect and set the CPU Type */
413 KiSetProcessorType();
415 /* Check if an FPU is present */
416 NpxPresent
= KiIsNpxPresent();
418 /* Initialize the Power Management Support for this PRCB */
419 PoInitializePrcb(Prcb
);
421 /* Bugcheck if this is a 386 CPU */
422 if (Prcb
->CpuType
== 3) KeBugCheckEx(UNSUPPORTED_PROCESSOR
, 0x386, 0, 0, 0);
424 /* Get the processor features for the CPU */
425 FeatureBits
= KiGetFeatureBits();
427 /* Set the default NX policy (opt-in) */
428 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTIN
;
430 /* Check if NPX is always on */
431 if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSON"))
433 /* Set it always on */
434 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSON
;
435 FeatureBits
|= KF_NX_ENABLED
;
437 else if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTOUT"))
439 /* Set it in opt-out mode */
440 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTOUT
;
441 FeatureBits
|= KF_NX_ENABLED
;
443 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTIN")) ||
444 (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE")))
446 /* Set the feature bits */
447 FeatureBits
|= KF_NX_ENABLED
;
449 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSOFF")) ||
450 (strstr(KeLoaderBlock
->LoadOptions
, "EXECUTE")))
452 /* Set disabled mode */
453 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSOFF
;
454 FeatureBits
|= KF_NX_DISABLED
;
457 /* Save feature bits */
458 Prcb
->FeatureBits
= FeatureBits
;
461 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
463 /* Get cache line information for this CPU */
464 KiGetCacheInformation();
466 /* Initialize spinlocks and DPC data */
467 KiInitSpinLocks(Prcb
, Number
);
469 /* Check if this is the Boot CPU */
473 KeNodeBlock
[0] = &KiNode0
;
474 Prcb
->ParentNode
= KeNodeBlock
[0];
475 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
477 /* Set boot-level flags */
478 KeI386NpxPresent
= NpxPresent
;
479 KeI386CpuType
= Prcb
->CpuType
;
480 KeI386CpuStep
= Prcb
->CpuStep
;
481 KeProcessorArchitecture
= PROCESSOR_ARCHITECTURE_INTEL
;
482 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
483 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
484 KeFeatureBits
= FeatureBits
;
485 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
486 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
488 /* Detect 8-byte compare exchange support */
489 if (!(KeFeatureBits
& KF_CMPXCHG8B
))
491 /* Copy the vendor string */
492 RtlCopyMemory(Vendor
, Prcb
->VendorString
, sizeof(Vendor
));
494 /* Bugcheck the system. Windows *requires* this */
495 KeBugCheckEx(UNSUPPORTED_PROCESSOR
,
496 (1 << 24 ) | (Prcb
->CpuType
<< 16) | Prcb
->CpuStep
,
502 /* Set the current MP Master KPRCB to the Boot PRCB */
503 Prcb
->MultiThreadSetMaster
= Prcb
;
505 /* Lower to APC_LEVEL */
506 KeLowerIrql(APC_LEVEL
);
508 /* Initialize some spinlocks */
509 KeInitializeSpinLock(&KiFreezeExecutionLock
);
510 KeInitializeSpinLock(&Ki486CompatibilityLock
);
512 /* Initialize portable parts of the OS */
515 /* Initialize the Idle Process and the Process Listhead */
516 InitializeListHead(&KiProcessListHead
);
517 PageDirectory
[0] = 0;
518 PageDirectory
[1] = 0;
519 KeInitializeProcess(InitProcess
,
524 InitProcess
->QuantumReset
= MAXCHAR
;
529 DPRINT1("SMP Boot support not yet present\n");
532 /* Setup the Idle Thread */
533 KeInitializeThread(InitProcess
,
541 InitThread
->NextProcessor
= Number
;
542 InitThread
->Priority
= HIGH_PRIORITY
;
543 InitThread
->State
= Running
;
544 InitThread
->Affinity
= 1 << Number
;
545 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
546 InitProcess
->ActiveProcessors
= 1 << Number
;
548 /* HACK for MmUpdatePageDir */
549 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
551 /* Set basic CPU Features that user mode can read */
552 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
553 (KeFeatureBits
& KF_MMX
) ? TRUE
: FALSE
;
554 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
555 (KeFeatureBits
& KF_CMPXCHG8B
) ? TRUE
: FALSE
;
556 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
557 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI
)) ? TRUE
: FALSE
;
558 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
559 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI64
)) ? TRUE
: FALSE
;
560 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
561 (KeFeatureBits
& KF_3DNOW
) ? TRUE
: FALSE
;
562 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
563 (KeFeatureBits
& KF_RDTSC
) ? TRUE
: FALSE
;
565 /* Set up the thread-related fields in the PRCB */
566 Prcb
->CurrentThread
= InitThread
;
567 Prcb
->NextThread
= NULL
;
568 Prcb
->IdleThread
= InitThread
;
570 /* Initialize the Kernel Executive */
571 ExpInitializeExecutive(Number
, LoaderBlock
);
573 /* Only do this on the boot CPU */
576 /* Calculate the time reciprocal */
577 KiTimeIncrementReciprocal
=
578 KiComputeReciprocal(KeMaximumIncrement
,
579 &KiTimeIncrementShiftCount
);
581 /* Update DPC Values in case they got updated by the executive */
582 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
583 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
584 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
586 /* Allocate the DPC Stack */
587 DpcStack
= MmCreateKernelStack(FALSE
, 0);
588 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
589 Prcb
->DpcStack
= DpcStack
;
591 /* Allocate the IOPM save area. */
592 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
595 if (!Ki386IopmSaveArea
)
597 /* Bugcheck. We need this for V86/VDM support. */
598 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
602 /* Raise to Dispatch */
603 KeRaiseIrql(DISPATCH_LEVEL
,
606 /* Set the Idle Priority to 0. This will jump into Phase 1 */
607 KeSetPriorityThread(InitThread
, 0);
609 /* If there's no thread scheduled, put this CPU in the Idle summary */
610 KiAcquirePrcbLock(Prcb
);
611 if (!Prcb
->NextThread
) KiIdleSummary
|= 1 << Number
;
612 KiReleasePrcbLock(Prcb
);
614 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
615 KeRaiseIrql(HIGH_LEVEL
,
617 LoaderBlock
->Prcb
= 0;
623 KiGetMachineBootPointers(IN PKGDTENTRY
*Gdt
,
628 KDESCRIPTOR GdtDescriptor
, IdtDescriptor
;
629 KGDTENTRY TssSelector
, PcrSelector
;
632 /* Get GDT and IDT descriptors */
633 Ke386GetGlobalDescriptorTable(&GdtDescriptor
.Limit
);
634 __sidt(&IdtDescriptor
.Limit
);
636 /* Save IDT and GDT */
637 *Gdt
= (PKGDTENTRY
)GdtDescriptor
.Base
;
638 *Idt
= (PKIDTENTRY
)IdtDescriptor
.Base
;
640 /* Get TSS and FS Selectors */
644 /* Get PCR Selector, mask it and get its GDT Entry */
645 PcrSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Fs
& ~RPL_MASK
));
647 /* Get the KPCR itself */
648 *Pcr
= (PKIPCR
)(ULONG_PTR
)(PcrSelector
.BaseLow
|
649 PcrSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
650 PcrSelector
.HighWord
.Bytes
.BaseHi
<< 24);
652 /* Get TSS Selector, mask it and get its GDT Entry */
653 TssSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Tr
& ~RPL_MASK
));
655 /* Get the KTSS itself */
656 *Tss
= (PKTSS
)(ULONG_PTR
)(TssSelector
.BaseLow
|
657 TssSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
658 TssSelector
.HighWord
.Bytes
.BaseHi
<< 24);
664 KiSystemStartupBootStack(VOID
)
668 /* Initialize the kernel for the current CPU */
669 KiInitializeKernel(&KiInitialProcess
.Pcb
,
670 (PKTHREAD
)KeLoaderBlock
->Thread
,
671 (PVOID
)(KeLoaderBlock
->KernelStack
& ~3),
672 (PKPRCB
)__readfsdword(KPCR_PRCB
),
673 KeNumberProcessors
- 1,
676 /* Set the priority of this thread to 0 */
677 Thread
= KeGetCurrentThread();
678 Thread
->Priority
= 0;
680 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
682 KeLowerIrql(DISPATCH_LEVEL
);
684 /* Set the right wait IRQL */
685 Thread
->WaitIrql
= DISPATCH_LEVEL
;
687 /* Jump into the idle loop */
693 KiMarkPageAsReadOnly(
696 PHARDWARE_PTE PointerPte
;
698 /* Make sure the address is page aligned */
699 ASSERT(ALIGN_DOWN_POINTER_BY(Address
, PAGE_SIZE
) == Address
);
701 /* Get the PTE address */
702 PointerPte
= ((PHARDWARE_PTE
)PTE_BASE
) + ((ULONG_PTR
)Address
/ PAGE_SIZE
);
703 ASSERT(PointerPte
->Valid
);
704 ASSERT(PointerPte
->Write
);
706 /* Set as read-only */
707 PointerPte
->Write
= 0;
709 /* Flush the TLB entry */
716 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
719 PKTHREAD InitialThread
;
723 KIDTENTRY NmiEntry
, DoubleFaultEntry
;
728 /* Boot cycles timestamp */
729 BootCycles
= __rdtsc();
731 /* Save the loader block and get the current CPU */
732 KeLoaderBlock
= LoaderBlock
;
733 Cpu
= KeNumberProcessors
;
736 /* If this is the boot CPU, set FS and the CPU Number*/
737 Ke386SetFs(KGDT_R0_PCR
);
738 __writefsdword(KPCR_PROCESSOR_NUMBER
, Cpu
);
740 /* Set the initial stack and idle thread as well */
741 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
742 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
745 /* Save the initial thread and stack */
746 InitialStack
= LoaderBlock
->KernelStack
;
747 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
749 /* Clean the APC List Head */
750 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
752 /* Initialize the machine type */
753 KiInitializeMachineType();
755 /* Skip initial setup if this isn't the Boot CPU */
756 if (Cpu
) goto AppCpuInit
;
758 /* Get GDT, IDT, PCR and TSS pointers */
759 KiGetMachineBootPointers(&Gdt
, &Idt
, &Pcr
, &Tss
);
761 /* Setup the TSS descriptors and entries */
762 Ki386InitializeTss(Tss
, Idt
, Gdt
);
764 /* Initialize the PCR */
765 RtlZeroMemory(Pcr
, PAGE_SIZE
);
772 (PVOID
)KiDoubleFaultStack
);
774 /* Set us as the current process */
775 InitialThread
->ApcState
.Process
= &KiInitialProcess
.Pcb
;
777 /* Clear DR6/7 to cleanup bootloader debugging */
778 __writefsdword(KPCR_TEB
, 0);
779 __writefsdword(KPCR_DR6
, 0);
780 __writefsdword(KPCR_DR7
, 0);
785 /* Load Ring 3 selectors for DS/ES */
786 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
787 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
789 /* Save NMI and double fault traps */
790 RtlCopyMemory(&NmiEntry
, &Idt
[2], sizeof(KIDTENTRY
));
791 RtlCopyMemory(&DoubleFaultEntry
, &Idt
[8], sizeof(KIDTENTRY
));
793 /* Copy kernel's trap handlers */
795 (PVOID
)KiIdtDescriptor
.Base
,
796 KiIdtDescriptor
.Limit
+ 1);
798 /* Restore NMI and double fault */
799 RtlCopyMemory(&Idt
[2], &NmiEntry
, sizeof(KIDTENTRY
));
800 RtlCopyMemory(&Idt
[8], &DoubleFaultEntry
, sizeof(KIDTENTRY
));
803 /* Loop until we can release the freeze lock */
806 /* Loop until execution can continue */
807 while (*(volatile PKSPIN_LOCK
*)&KiFreezeExecutionLock
== (PVOID
)1);
808 } while(InterlockedBitTestAndSet((PLONG
)&KiFreezeExecutionLock
, 0));
810 /* Setup CPU-related fields */
811 __writefsdword(KPCR_NUMBER
, Cpu
);
812 __writefsdword(KPCR_SET_MEMBER
, 1 << Cpu
);
813 __writefsdword(KPCR_SET_MEMBER_COPY
, 1 << Cpu
);
814 __writefsdword(KPCR_PRCB_SET_MEMBER
, 1 << Cpu
);
816 /* Initialize the Processor with HAL */
817 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
819 /* Set active processors */
820 KeActiveProcessors
|= __readfsdword(KPCR_SET_MEMBER
);
821 KeNumberProcessors
++;
823 /* Check if this is the boot CPU */
826 /* Initialize debugging system */
827 KdInitSystem(0, KeLoaderBlock
);
829 /* Check for break-in */
830 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
832 /* Make the lowest page of the boot and double fault stack read-only */
833 KiMarkPageAsReadOnly(P0BootStackData
);
834 KiMarkPageAsReadOnly(KiDoubleFaultStackData
);
837 /* Raise to HIGH_LEVEL */
838 KeRaiseIrql(HIGH_LEVEL
,
841 /* Switch to new kernel stack and start kernel bootstrapping */
842 KiSwitchToBootStack(InitialStack
& ~3);