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 * Timo Kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES *****************************************************************/
16 #define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \
19 /* GLOBALS *******************************************************************/
21 /* Function pointer for early debug prints */
22 ULONG (*FrLdrDbgPrint
)(const char *Format
, ...);
24 /* Spinlocks used only on X86 */
25 KSPIN_LOCK KiFreezeExecutionLock
;
27 /* BIOS Memory Map. Not NTLDR-compliant yet */
28 extern ULONG KeMemoryMapRangeCount
;
29 extern ADDRESS_RANGE KeMemoryMap
[64];
33 /* Boot and double-fault/NMI/DPC stack */
34 UCHAR
DECLSPEC_ALIGN(16) P0BootStackData
[KERNEL_STACK_SIZE
] = {0};
35 UCHAR
DECLSPEC_ALIGN(16) KiDoubleFaultStackData
[KERNEL_STACK_SIZE
] = {0};
36 ULONG_PTR P0BootStack
= (ULONG_PTR
)&P0BootStackData
[KERNEL_STACK_SIZE
];
37 ULONG_PTR KiDoubleFaultStack
= (ULONG_PTR
)&KiDoubleFaultStackData
[KERNEL_STACK_SIZE
];
39 /* FUNCTIONS *****************************************************************/
43 KiInitMachineDependent(VOID
)
45 /* Check for large page support */
46 if (KeFeatureBits
& KF_LARGE_PAGE
)
48 /* FIXME: Support this */
49 DPRINT1("Large Page support detected but not yet taken advantage of!\n");
52 /* Check for global page support */
53 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
55 /* FIXME: Support this */
56 DPRINT1("Global Page support detected but not yet taken advantage of!\n");
59 /* Check if we have MTRR */
60 if (KeFeatureBits
& KF_MTRR
)
62 /* FIXME: Support this */
63 DPRINT1("MTRR support detected but not yet taken advantage of!\n");
66 /* Check for PAT and/or MTRR support */
67 if (KeFeatureBits
& KF_PAT
)
69 /* FIXME: Support this */
70 DPRINT1("PAT support detected but not yet taken advantage of!\n");
78 KiInitializePcr(IN PKIPCR Pcr
,
79 IN ULONG ProcessorNumber
,
80 IN PKTHREAD IdleThread
,
83 KDESCRIPTOR GdtDescriptor
= {{0},0,0}, IdtDescriptor
= {{0},0,0};
84 PKGDTENTRY64 TssEntry
;
87 /* Zero out the PCR */
88 RtlZeroMemory(Pcr
, PAGE_SIZE
);
90 /* Set pointers to ourselves */
91 Pcr
->Self
= (PKPCR
)Pcr
;
92 Pcr
->CurrentPrcb
= &Pcr
->Prcb
;
94 /* Set the PCR Version */
95 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
96 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
98 /* Set the PRCB Version */
99 Pcr
->Prcb
.MajorVersion
= 1;
100 Pcr
->Prcb
.MinorVersion
= 1;
102 /* Set the Build Type */
103 Pcr
->Prcb
.BuildType
= 0;
105 Pcr
->Prcb
.BuildType
|= PRCB_BUILD_UNIPROCESSOR
;
108 Pcr
->Prcb
.BuildType
|= PRCB_BUILD_DEBUG
;
111 /* Set the Processor Number and current Processor Mask */
112 Pcr
->Prcb
.Number
= (UCHAR
)ProcessorNumber
;
113 Pcr
->Prcb
.SetMember
= 1 << ProcessorNumber
;
115 /* Get GDT and IDT descriptors */
116 __sgdt(&GdtDescriptor
.Limit
);
117 __sidt(&IdtDescriptor
.Limit
);
118 Pcr
->GdtBase
= (PVOID
)GdtDescriptor
.Base
;
119 Pcr
->IdtBase
= (PKIDTENTRY
)IdtDescriptor
.Base
;
121 /* Get TSS Selector */
123 ASSERT(Tr
== KGDT64_SYS_TSS
);
126 TssEntry
= KiGetGdtEntry(Pcr
->GdtBase
, Tr
);
128 /* Get the KTSS itself */
129 Pcr
->TssBase
= KiGetGdtDescriptorBase(TssEntry
);
131 Pcr
->Prcb
.RspBase
= Pcr
->TssBase
->Rsp0
; // FIXME
134 Pcr
->Prcb
.DpcStack
= DpcStack
;
136 /* Setup the processor set */
137 Pcr
->Prcb
.MultiThreadProcessorSet
= Pcr
->Prcb
.SetMember
;
139 /* Clear DR6/7 to cleanup bootloader debugging */
140 Pcr
->Prcb
.ProcessorState
.SpecialRegisters
.KernelDr6
= 0;
141 Pcr
->Prcb
.ProcessorState
.SpecialRegisters
.KernelDr7
= 0;
143 /* Set the Current Thread */
144 Pcr
->Prcb
.CurrentThread
= IdleThread
;
146 /* Start us out at PASSIVE_LEVEL */
147 Pcr
->Irql
= PASSIVE_LEVEL
;
148 KeSetCurrentIrql(PASSIVE_LEVEL
);
154 KiInitializeCpuFeatures(ULONG Cpu
)
158 /* Get the processor features for this CPU */
159 FeatureBits
= KiGetFeatureBits();
161 /* Check if we support all needed features */
162 if ((FeatureBits
& REQUIRED_FEATURE_BITS
) != REQUIRED_FEATURE_BITS
)
164 /* If not, bugcheck system */
165 FrLdrDbgPrint("CPU doesn't have needed features! Has: 0x%x, required: 0x%x\n",
166 FeatureBits
, REQUIRED_FEATURE_BITS
);
170 /* Set DEP to always on */
171 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSON
;
172 FeatureBits
|= KF_NX_ENABLED
;
174 /* Save feature bits */
175 KeGetCurrentPrcb()->FeatureBits
= FeatureBits
;
177 /* Enable fx save restore support */
178 __writecr4(__readcr4() | CR4_FXSR
);
180 /* Enable XMMI exceptions */
181 __writecr4(__readcr4() | CR4_XMMEXCPT
);
183 /* Enable Write-Protection */
184 __writecr0(__readcr0() | CR0_WP
);
186 /* Disable fpu monitoring */
187 __writecr0(__readcr0() & ~CR0_MP
);
189 /* Disable x87 fpu exceptions */
190 __writecr0(__readcr0() & ~CR0_NE
);
196 KiInitializeKernel(IN PKPROCESS InitProcess
,
197 IN PKTHREAD InitThread
,
201 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
203 ULONG PageDirectory
[2];
206 /* Detect and set the CPU Type */
207 KiSetProcessorType();
209 /* Initialize the Power Management Support for this PRCB */
210 // PoInitializePrcb(Prcb);
213 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
215 /* Get cache line information for this CPU */
216 KiGetCacheInformation();
218 /* Initialize spinlocks and DPC data */
219 KiInitSpinLocks(Prcb
, Number
);
221 /* Check if this is the Boot CPU */
225 KeNodeBlock
[0] = &KiNode0
;
226 Prcb
->ParentNode
= KeNodeBlock
[0];
227 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
229 /* Set boot-level flags */
230 KeProcessorArchitecture
= PROCESSOR_ARCHITECTURE_AMD64
;
231 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
232 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
234 /* Set the current MP Master KPRCB to the Boot PRCB */
235 Prcb
->MultiThreadSetMaster
= Prcb
;
237 /* Lower to APC_LEVEL */
238 KeLowerIrql(APC_LEVEL
);
240 /* Initialize some spinlocks */
241 KeInitializeSpinLock(&KiFreezeExecutionLock
);
243 /* Initialize portable parts of the OS */
246 /* Initialize the Idle Process and the Process Listhead */
247 InitializeListHead(&KiProcessListHead
);
248 PageDirectory
[0] = 0;
249 PageDirectory
[1] = 0;
250 KeInitializeProcess(InitProcess
,
255 InitProcess
->QuantumReset
= MAXCHAR
;
260 DPRINT1("SMP Boot support not yet present\n");
263 /* HACK for MmUpdatePageDir */
264 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
266 /* Setup the Idle Thread */
267 KeInitializeThread(InitProcess
,
276 InitThread
->NextProcessor
= Number
;
277 InitThread
->Priority
= HIGH_PRIORITY
;
278 InitThread
->State
= Running
;
279 InitThread
->Affinity
= 1 << Number
;
280 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
281 InitProcess
->ActiveProcessors
= 1 << Number
;
283 /* Set basic CPU Features that user mode can read */
284 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
285 (KeFeatureBits
& KF_MMX
) ? TRUE
: FALSE
;
286 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
287 (KeFeatureBits
& KF_CMPXCHG8B
) ? TRUE
: FALSE
;
288 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
289 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI
)) ? TRUE
: FALSE
;
290 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
291 ((KeFeatureBits
& KF_FXSR
) && (KeFeatureBits
& KF_XMMI64
)) ? TRUE
: FALSE
;
292 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
293 (KeFeatureBits
& KF_3DNOW
) ? TRUE
: FALSE
;
294 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
295 (KeFeatureBits
& KF_RDTSC
) ? TRUE
: FALSE
;
297 /* Set up the thread-related fields in the PRCB */
298 Prcb
->CurrentThread
= InitThread
;
299 Prcb
->NextThread
= NULL
;
300 Prcb
->IdleThread
= InitThread
;
302 /* Initialize the Kernel Executive */
303 ExpInitializeExecutive(Number
, LoaderBlock
);
305 /* Only do this on the boot CPU */
308 /* Calculate the time reciprocal */
309 KiTimeIncrementReciprocal
=
310 KiComputeReciprocal(KeMaximumIncrement
,
311 &KiTimeIncrementShiftCount
);
313 /* Update DPC Values in case they got updated by the executive */
314 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
315 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
316 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
318 /* Allocate the DPC Stack */
319 DpcStack
= MmCreateKernelStack(FALSE
, 0);
320 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
321 Prcb
->DpcStack
= DpcStack
;
323 /* Allocate the IOPM save area. */
324 // Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
326 // TAG('K', 'e', ' ', ' '));
327 // if (!Ki386IopmSaveArea)
329 // /* Bugcheck. We need this for V86/VDM support. */
330 // KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
334 /* Raise to Dispatch */
335 KfRaiseIrql(DISPATCH_LEVEL
);
337 /* Set the Idle Priority to 0. This will jump into Phase 1 */
338 KeSetPriorityThread(InitThread
, 0);
340 /* If there's no thread scheduled, put this CPU in the Idle summary */
341 KiAcquirePrcbLock(Prcb
);
342 if (!Prcb
->NextThread
) KiIdleSummary
|= 1 << Number
;
343 KiReleasePrcbLock(Prcb
);
345 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
346 KfRaiseIrql(HIGH_LEVEL
);
347 LoaderBlock
->Prcb
= 0;
352 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
355 PKTHREAD InitialThread
;
356 ULONG64 InitialStack
;
360 FrLdrDbgPrint
= LoaderBlock
->u
.I386
.CommonDataArea
;
361 FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
363 /* HACK, because freeldr maps page 0 */
364 MiAddressToPte((PVOID
)0)->u
.Hard
.Valid
= 0;
366 /* Save the loader block */
367 KeLoaderBlock
= LoaderBlock
;
369 /* Get the current CPU number */
370 Cpu
= KeNumberProcessors
++; // FIXME
372 /* LoaderBlock initialization for Cpu 0 */
375 /* Set the initial stack, idle thread and process */
376 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
377 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
378 LoaderBlock
->Process
= (ULONG_PTR
)&KiInitialProcess
.Pcb
;
379 LoaderBlock
->Prcb
= (ULONG_PTR
)&KiInitialPcr
.Prcb
;
382 /* Get Pcr from loader block */
383 Pcr
= CONTAINING_RECORD(LoaderBlock
->Prcb
, KIPCR
, Prcb
);
385 /* Set the PRCB for this Processor */
386 KiProcessorBlock
[Cpu
] = &Pcr
->Prcb
;
389 __writemsr(X86_MSR_GSBASE
, (ULONG64
)Pcr
);
390 __writemsr(X86_MSR_KERNEL_GSBASE
, (ULONG64
)Pcr
);
395 /* Align stack to 16 bytes */
396 LoaderBlock
->KernelStack
&= ~(16 - 1);
398 /* Save the initial thread and stack */
399 InitialStack
= LoaderBlock
->KernelStack
; // Checkme
400 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
402 /* Clean the APC List Head */
403 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
405 /* Set us as the current process */
406 InitialThread
->ApcState
.Process
= (PVOID
)LoaderBlock
->Process
;
408 /* Initialize the PCR */
409 KiInitializePcr(Pcr
, Cpu
, InitialThread
, (PVOID
)KiDoubleFaultStack
);
411 /* Initialize the CPU features */
412 KiInitializeCpuFeatures(Cpu
);
414 /* Initial setup for the boot CPU */
417 /* Setup the TSS descriptors and entries */
418 KiInitializeTss(Pcr
->TssBase
, InitialStack
);
423 /* HACK: misuse this function to pass a function pointer to kdcom */
424 KdDebuggerInitialize1((PVOID
)FrLdrDbgPrint
);
426 /* Initialize debugging system */
427 KdInitSystem(0, KeLoaderBlock
);
429 /* Check for break-in */
430 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
432 /* Hack! Wait for the debugger! */
434 while (!KdPollBreakIn());
435 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
439 DPRINT("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
440 Pcr
, Pcr
->GdtBase
, Pcr
->IdtBase
, Pcr
->TssBase
);
443 while (InterlockedBitTestAndSet64((PLONG64
)&KiFreezeExecutionLock
, 0))
445 /* Loop until lock is free */
446 while ((*(volatile KSPIN_LOCK
*)&KiFreezeExecutionLock
) & 1);
449 /* Initialize the Processor with HAL */
450 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
452 /* Set processor as active */
453 KeActiveProcessors
|= 1 << Cpu
;
456 InterlockedAnd64((PLONG64
)&KiFreezeExecutionLock
, 0);
458 /* Raise to HIGH_LEVEL */
459 KfRaiseIrql(HIGH_LEVEL
);
461 /* Switch to new kernel stack and start kernel bootstrapping */
462 KiSetupStackAndInitializeKernel(&KiInitialProcess
.Pcb
,
473 KiInitializeKernelAndGotoIdleLoop(IN PKPROCESS InitProcess
,
474 IN PKTHREAD InitThread
,
478 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
480 // DbgBreakPointWithStatus(0);
482 /* Initialize kernel */
483 KiInitializeKernel(InitProcess
,
490 /* Set the priority of this thread to 0 */
491 InitThread
->Priority
= 0;
493 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
495 KeLowerIrql(DISPATCH_LEVEL
);
497 /* Set the right wait IRQL */
498 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
500 /* Jump into the idle loop */