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 *****************************************************************/
15 /* GLOBALS *******************************************************************/
17 /* Spinlocks used only on X86 */
18 KSPIN_LOCK KiFreezeExecutionLock
;
19 KSPIN_LOCK Ki486CompatibilityLock
;
21 /* FUNCTIONS *****************************************************************/
25 KiInitMachineDependent(VOID
)
29 BOOLEAN FbCaching
= FALSE
;
33 PFX_SAVE_AREA FxSaveArea
;
34 ULONG MXCsrMask
= 0xFFBF, NewMask
;
36 /* Check for large page support */
37 if (KeFeatureBits
& KF_LARGE_PAGE
)
39 /* FIXME: Support this */
40 DPRINT1("Your machine supports PGE but ReactOS doesn't yet.\n");
43 /* Check for global page support */
44 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
46 /* Do an IPI to enable it on all CPUs */
47 CpuCount
= KeNumberProcessors
;
48 KeIpiGenericCall(Ki386EnableGlobalPage
, (ULONG_PTR
)&CpuCount
);
51 /* Check for PAT and/or MTRR support */
52 if (KeFeatureBits
& (KF_PAT
| KF_MTRR
))
54 /* FIXME: ROS HAL Doesn't initialize this! */
56 Status
= STATUS_UNSUCCESSFUL
;
58 /* Query the HAL to make sure we can use it */
59 Status
= HalQuerySystemInformation(HalFrameBufferCachingInformation
,
64 if ((NT_SUCCESS(Status
)) && (FbCaching
))
66 /* We can't, disable it */
67 KeFeatureBits
&= ~(KF_PAT
| KF_MTRR
);
71 /* Check for PAT support and enable it */
72 if (KeFeatureBits
& KF_PAT
) KiInitializePAT();
74 /* Assume no errata for now */
75 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = 0;
77 /* If there's no NPX, then we're emulating the FPU */
78 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] =
81 /* Check if there's no NPX, so that we can disable associated features */
82 if (!KeI386NpxPresent
)
84 /* Remove NPX-related bits */
85 KeFeatureBits
&= ~(KF_XMMI64
| KF_XMMI
| KF_FXSR
| KF_MMX
);
87 /* Disable kernel flags */
88 KeI386FxsrPresent
= KeI386XMMIPresent
= FALSE
;
90 /* Disable processor features that might've been set until now */
91 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] =
92 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
93 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
94 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
95 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] = 0;
98 /* Check for CR4 support */
99 if (KeFeatureBits
& KF_CR4
)
101 /* Do an IPI call to enable the Debug Exceptions */
102 CpuCount
= KeNumberProcessors
;
103 KeIpiGenericCall(Ki386EnableDE
, (ULONG_PTR
)&CpuCount
);
106 /* Check if FXSR was found */
107 if (KeFeatureBits
& KF_FXSR
)
109 /* Do an IPI call to enable the FXSR */
110 CpuCount
= KeNumberProcessors
;
111 KeIpiGenericCall(Ki386EnableFxsr
, (ULONG_PTR
)&CpuCount
);
113 /* Check if XMM was found too */
114 if (KeFeatureBits
& KF_XMMI
)
116 /* Do an IPI call to enable XMMI exceptions */
117 CpuCount
= KeNumberProcessors
;
118 KeIpiGenericCall(Ki386EnableXMMIExceptions
, (ULONG_PTR
)&CpuCount
);
120 /* FIXME: Implement and enable XMM Page Zeroing for Mm */
122 /* Patch the RtlPrefetchMemoryNonTemporal routine to enable it */
123 Protect
= MmGetPageProtect(NULL
, RtlPrefetchMemoryNonTemporal
);
124 MmSetPageProtect(NULL
,
125 RtlPrefetchMemoryNonTemporal
,
126 Protect
| PAGE_IS_WRITABLE
);
127 *(PCHAR
)RtlPrefetchMemoryNonTemporal
= 0x90;
128 MmSetPageProtect(NULL
, RtlPrefetchMemoryNonTemporal
, Protect
);
132 /* Check for, and enable SYSENTER support */
133 KiRestoreFastSyscallReturnState();
136 i
= KeActiveProcessors
;
137 for (Affinity
= 1; i
; Affinity
<<= 1)
139 /* Check if this is part of the set */
142 /* Run on this CPU */
144 KeSetSystemAffinityThread(Affinity
);
146 /* Reset MHz to 0 for this CPU */
147 KeGetCurrentPrcb()->MHz
= 0;
149 /* Check if we can use RDTSC */
150 if (KeFeatureBits
& KF_RDTSC
)
152 /* Start sampling loop */
162 /* Check if we have MTRR without PAT */
163 if (!(KeFeatureBits
& KF_PAT
) && (KeFeatureBits
& KF_MTRR
))
165 /* Then manually initialize MTRR for the CPU */
166 KiInitializeMTRR((BOOLEAN
)i
);
169 /* Check if we have AMD MTRR and initialize it for the CPU */
170 if (KeFeatureBits
& KF_AMDK6MTRR
) KiAmdK6InitializeMTRR();
172 /* Check if this is a buggy Pentium and apply the fixup if so */
173 if (KiI386PentiumLockErrataPresent
) KiI386PentiumLockErrataFixup();
175 /* Get the current thread NPX state */
177 ((ULONG_PTR
)KeGetCurrentThread()->InitialStack
-
180 /* Clear initial MXCsr mask */
181 FxSaveArea
->U
.FxArea
.MXCsrMask
= 0;
183 /* Save the current NPX State */
185 asm volatile("fxsave %0\n\t" : "=m" (*FxSaveArea
));
187 __asm fxsave
[FxSaveArea
]
189 /* Check if the current mask doesn't match the reserved bits */
190 if (FxSaveArea
->U
.FxArea
.MXCsrMask
!= MXCsrMask
)
192 /* Then use whatever it's holding */
193 MXCsrMask
= FxSaveArea
->U
.FxArea
.MXCsrMask
;
196 /* Check if nobody set the kernel-wide mask */
199 /* Then use the one we calculated above */
204 /* Use the existing mask */
205 NewMask
= KiMXCsrMask
;
207 /* Was it set to the same value we found now? */
208 if (NewMask
!= MXCsrMask
)
210 /* No, something is definitely wrong */
211 KEBUGCHECKEX(MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED
,
219 /* Now set the kernel mask */
220 KiMXCsrMask
= NewMask
& MXCsrMask
;
224 /* Return affinity back to where it was */
225 KeRevertToUserAffinityThread();
227 /* NT allows limiting the duration of an ISR with a registry key */
228 if (KiTimeLimitIsrMicroseconds
)
231 DPRINT1("ISR Time Limit not yet supported\n");
237 KiInitializePcr(IN ULONG ProcessorNumber
,
242 IN PKTHREAD IdleThread
,
246 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
247 Pcr
->NtTib
.StackBase
= 0;
248 Pcr
->NtTib
.StackLimit
= 0;
251 /* Set the Current Thread */
252 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
254 /* Set pointers to ourselves */
255 Pcr
->Self
= (PKPCR
)Pcr
;
256 Pcr
->Prcb
= &Pcr
->PrcbData
;
258 /* Set the PCR Version */
259 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
260 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
262 /* Set the PCRB Version */
263 Pcr
->PrcbData
.MajorVersion
= 1;
264 Pcr
->PrcbData
.MinorVersion
= 1;
266 /* Set the Build Type */
267 Pcr
->PrcbData
.BuildType
= 0;
269 /* Set the Processor Number and current Processor Mask */
270 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
271 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
273 /* Set the PRCB for this Processor */
274 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
276 /* Start us out at PASSIVE_LEVEL */
277 Pcr
->Irql
= PASSIVE_LEVEL
;
279 /* Set the GDI, IDT, TSS and DPC Stack */
280 Pcr
->GDT
= (PVOID
)Gdt
;
283 Pcr
->PrcbData
.DpcStack
= DpcStack
;
288 KiInitializeKernel(IN PKPROCESS InitProcess
,
289 IN PKTHREAD InitThread
,
293 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
297 LARGE_INTEGER PageDirectory
;
300 /* Detect and set the CPU Type */
301 KiSetProcessorType();
303 /* Set CR0 features based on detected CPU */
306 /* Check if an FPU is present */
307 NpxPresent
= KiIsNpxPresent();
309 /* Initialize the Power Management Support for this PRCB */
310 PoInitializePrcb(Prcb
);
312 /* Bugcheck if this is a 386 CPU */
313 if (Prcb
->CpuType
== 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
315 /* Get the processor features for the CPU */
316 FeatureBits
= KiGetFeatureBits();
318 /* Save feature bits */
319 Prcb
->FeatureBits
= FeatureBits
;
322 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
324 /* Get cache line information for this CPU */
325 KiGetCacheInformation();
327 /* Initialize spinlocks and DPC data */
328 KiInitSpinLocks(Prcb
, Number
);
330 /* Check if this is the Boot CPU */
334 KeNodeBlock
[0] = &KiNode0
;
335 Prcb
->ParentNode
= KeNodeBlock
[0];
336 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
338 /* Set boot-level flags */
339 KeI386NpxPresent
= NpxPresent
;
340 KeI386CpuType
= Prcb
->CpuType
;
341 KeI386CpuStep
= Prcb
->CpuStep
;
342 KeProcessorArchitecture
= 0;
343 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
344 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
345 KeFeatureBits
= FeatureBits
;
346 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
347 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
349 /* Set the current MP Master KPRCB to the Boot PRCB */
350 Prcb
->MultiThreadSetMaster
= Prcb
;
352 /* Lower to APC_LEVEL */
353 KfLowerIrql(APC_LEVEL
);
355 /* Initialize some spinlocks */
356 KeInitializeSpinLock(&KiFreezeExecutionLock
);
357 KeInitializeSpinLock(&Ki486CompatibilityLock
);
359 /* Initialize portable parts of the OS */
362 /* Initialize the Idle Process and the Process Listhead */
363 InitializeListHead(&KiProcessListHead
);
364 PageDirectory
.QuadPart
= 0;
365 KeInitializeProcess(InitProcess
,
370 InitProcess
->QuantumReset
= MAXCHAR
;
375 DPRINT1("SMP Boot support not yet present\n");
378 /* Initialize Kernel Memory Address Space */
379 MmInit1(FirstKrnlPhysAddr
,
382 (PADDRESS_RANGE
)&KeMemoryMap
,
383 KeMemoryMapRangeCount
,
386 /* Sets up the Text Sections of the Kernel and HAL for debugging */
389 /* Setup the Idle Thread */
390 KeInitializeThread(InitProcess
,
398 InitThread
->NextProcessor
= Number
;
399 InitThread
->Priority
= HIGH_PRIORITY
;
400 InitThread
->State
= Running
;
401 InitThread
->Affinity
= 1 << Number
;
402 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
403 InitProcess
->ActiveProcessors
= 1 << Number
;
405 /* HACK for MmUpdatePageDir */
406 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
408 /* Set up the thread-related fields in the PRCB */
409 Prcb
->CurrentThread
= InitThread
;
410 Prcb
->NextThread
= NULL
;
411 Prcb
->IdleThread
= InitThread
;
413 /* Initialize the Kernel Executive */
414 ExpInitializeExecutive(Number
, LoaderBlock
);
416 /* Only do this on the boot CPU */
419 /* Calculate the time reciprocal */
420 KiTimeIncrementReciprocal
=
421 KiComputeReciprocal(KeMaximumIncrement
,
422 &KiTimeIncrementShiftCount
);
424 /* Update DPC Values in case they got updated by the executive */
425 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
426 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
427 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
429 /* Allocate the DPC Stack */
430 DpcStack
= MmCreateKernelStack(FALSE
);
431 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
432 Prcb
->DpcStack
= DpcStack
;
434 /* Allocate the IOPM save area. */
435 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
437 TAG('K', 'e', ' ', ' '));
438 if (!Ki386IopmSaveArea
)
440 /* Bugcheck. We need this for V86/VDM support. */
441 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
445 /* Raise to Dispatch */
446 KfRaiseIrql(DISPATCH_LEVEL
);
448 /* Set the Idle Priority to 0. This will jump into Phase 1 */
449 KeSetPriorityThread(InitThread
, 0);
451 /* If there's no thread scheduled, put this CPU in the Idle summary */
452 if (!Prcb
->NextThread
) KiIdleSummary
|= 1 << Number
;
454 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
455 KfRaiseIrql(HIGH_LEVEL
);
456 LoaderBlock
->Prcb
= 0;
461 KiGetMachineBootPointers(IN PKGDTENTRY
*Gdt
,
466 KDESCRIPTOR GdtDescriptor
, IdtDescriptor
;
467 KGDTENTRY TssSelector
, PcrSelector
;
470 /* Get GDT and IDT descriptors */
471 Ke386GetGlobalDescriptorTable(GdtDescriptor
);
472 Ke386GetInterruptDescriptorTable(IdtDescriptor
);
474 /* Save IDT and GDT */
475 *Gdt
= (PKGDTENTRY
)GdtDescriptor
.Base
;
476 *Idt
= (PKIDTENTRY
)IdtDescriptor
.Base
;
478 /* Get TSS and FS Selectors */
480 if (Tr
!= KGDT_TSS
) Tr
= KGDT_TSS
; // FIXME: HACKHACK
483 /* Get PCR Selector, mask it and get its GDT Entry */
484 PcrSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Fs
& ~RPL_MASK
));
486 /* Get the KPCR itself */
487 *Pcr
= (PKIPCR
)(ULONG_PTR
)(PcrSelector
.BaseLow
|
488 PcrSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
489 PcrSelector
.HighWord
.Bytes
.BaseHi
<< 24);
491 /* Get TSS Selector, mask it and get its GDT Entry */
492 TssSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Tr
& ~RPL_MASK
));
494 /* Get the KTSS itself */
495 *Tss
= (PKTSS
)(ULONG_PTR
)(TssSelector
.BaseLow
|
496 TssSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
497 TssSelector
.HighWord
.Bytes
.BaseHi
<< 24);
502 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
505 PKTHREAD InitialThread
;
512 /* Save the loader block and get the current CPU */
513 KeLoaderBlock
= LoaderBlock
;
514 Cpu
= KeNumberProcessors
;
517 /* If this is the boot CPU, set FS and the CPU Number*/
518 Ke386SetFs(KGDT_R0_PCR
);
519 __writefsdword(KPCR_PROCESSOR_NUMBER
, Cpu
);
521 /* Set the initial stack and idle thread as well */
522 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
523 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
526 /* Save the initial thread and stack */
527 InitialStack
= LoaderBlock
->KernelStack
;
528 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
530 /* Clean the APC List Head */
531 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
533 /* Initialize the machine type */
534 KiInitializeMachineType();
536 /* Skip initial setup if this isn't the Boot CPU */
537 if (Cpu
) goto AppCpuInit
;
539 /* Get GDT, IDT, PCR and TSS pointers */
540 KiGetMachineBootPointers(&Gdt
, &Idt
, &Pcr
, &Tss
);
542 /* Setup the TSS descriptors and entries */
543 Ki386InitializeTss(Tss
, Idt
, Gdt
);
545 /* Initialize the PCR */
546 RtlZeroMemory(Pcr
, PAGE_SIZE
);
555 /* Set us as the current process */
556 InitialThread
->ApcState
.Process
= &KiInitialProcess
.Pcb
;
558 /* Clear DR6/7 to cleanup bootloader debugging */
559 __writefsdword(KPCR_TEB
, 0);
560 __writefsdword(KPCR_DR6
, 0);
561 __writefsdword(KPCR_DR7
, 0);
563 /* Load Ring 3 selectors for DS/ES */
564 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
565 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
568 /* Loop until we can release the freeze lock */
571 /* Loop until execution can continue */
572 while ((volatile KSPIN_LOCK
)KiFreezeExecutionLock
== 1);
573 } while(InterlockedBitTestAndSet((PLONG
)&KiFreezeExecutionLock
, 0));
575 /* Setup CPU-related fields */
576 __writefsdword(KPCR_NUMBER
, Cpu
);
577 __writefsdword(KPCR_SET_MEMBER
, 1 << Cpu
);
578 __writefsdword(KPCR_SET_MEMBER_COPY
, 1 << Cpu
);
579 __writefsdword(KPCR_PRCB_SET_MEMBER
, 1 << Cpu
);
581 /* Initialize the Processor with HAL */
582 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
584 /* Set active processors */
585 KeActiveProcessors
|= __readfsdword(KPCR_SET_MEMBER
);
586 KeNumberProcessors
++;
588 /* Check if this is the boot CPU */
591 /* Initialize debugging system */
592 KdInitSystem(0, KeLoaderBlock
);
594 /* Check for break-in */
595 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
598 /* Raise to HIGH_LEVEL */
599 KfRaiseIrql(HIGH_LEVEL
);
601 /* Align stack and make space for the trap frame and NPX frame */
602 InitialStack
&= ~KTRAP_FRAME_ALIGN
;
604 __asm__
__volatile__("movl %0,%%esp" : :"r" (InitialStack
));
605 __asm__
__volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH
+
608 __asm__
__volatile__("push %0" : :"r" (CR0_EM
+ CR0_TS
+ CR0_MP
));
610 __asm mov esp
, InitialStack
;
611 __asm sub esp
, NPX_FRAME_LENGTH
+ KTRAP_FRAME_ALIGN
+ KTRAP_FRAME_LENGTH
;
612 __asm push CR0_EM
+ CR0_TS
+ CR0_MP
615 /* Call main kernel initialization */
616 KiInitializeKernel(&KiInitialProcess
.Pcb
,
619 (PKPRCB
)__readfsdword(KPCR_PRCB
),
623 /* Set the priority of this thread to 0 */
624 KeGetCurrentThread()->Priority
= 0;
626 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
628 KfLowerIrql(DISPATCH_LEVEL
);
630 /* Set the right wait IRQL */
631 KeGetCurrentThread()->WaitIrql
= DISPATCH_LEVEL
;
633 /* Set idle thread as running on UP builds */
635 KeGetCurrentThread()->State
= Running
;
638 /* Jump into the idle loop */