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 KiInitializePcr(IN ULONG ProcessorNumber
,
30 IN PKTHREAD IdleThread
,
34 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
35 Pcr
->NtTib
.StackBase
= 0;
36 Pcr
->NtTib
.StackLimit
= 0;
39 /* Set the Current Thread */
40 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
42 /* Set pointers to ourselves */
43 Pcr
->Self
= (PKPCR
)Pcr
;
44 Pcr
->Prcb
= &Pcr
->PrcbData
;
46 /* Set the PCR Version */
47 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
48 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
50 /* Set the PCRB Version */
51 Pcr
->PrcbData
.MajorVersion
= 1;
52 Pcr
->PrcbData
.MinorVersion
= 1;
54 /* Set the Build Type */
55 Pcr
->PrcbData
.BuildType
= 0;
57 /* Set the Processor Number and current Processor Mask */
58 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
59 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
61 /* Set the PRCB for this Processor */
62 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
64 /* Start us out at PASSIVE_LEVEL */
65 Pcr
->Irql
= PASSIVE_LEVEL
;
67 /* Set the GDI, IDT, TSS and DPC Stack */
68 Pcr
->GDT
= (PVOID
)Gdt
;
71 Pcr
->PrcbData
.DpcStack
= DpcStack
;
76 KiInitializeKernel(IN PKPROCESS InitProcess
,
77 IN PKTHREAD InitThread
,
81 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
85 LARGE_INTEGER PageDirectory
;
88 /* Detect and set the CPU Type */
91 /* Set CR0 features based on detected CPU */
94 /* Check if an FPU is present */
95 NpxPresent
= KiIsNpxPresent();
97 /* Initialize the Power Management Support for this PRCB */
98 PoInitializePrcb(Prcb
);
100 /* Bugcheck if this is a 386 CPU */
101 if (Prcb
->CpuType
== 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
103 /* Get the processor features for the CPU */
104 FeatureBits
= KiGetFeatureBits();
106 /* Save feature bits */
107 Prcb
->FeatureBits
= FeatureBits
;
110 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
112 /* Get cache line information for this CPU */
113 KiGetCacheInformation();
115 /* Initialize spinlocks and DPC data */
116 KiInitSpinLocks(Prcb
, Number
);
118 /* Check if this is the Boot CPU */
122 KeNodeBlock
[0] = &KiNode0
;
123 Prcb
->ParentNode
= KeNodeBlock
[0];
124 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
126 /* Set boot-level flags */
127 KeI386NpxPresent
= NpxPresent
;
128 KeI386CpuType
= Prcb
->CpuType
;
129 KeI386CpuStep
= Prcb
->CpuStep
;
130 KeProcessorArchitecture
= 0;
131 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
132 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
133 KeFeatureBits
= FeatureBits
;
134 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
135 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
137 /* Set the current MP Master KPRCB to the Boot PRCB */
138 Prcb
->MultiThreadSetMaster
= Prcb
;
140 /* Lower to APC_LEVEL */
141 KfLowerIrql(APC_LEVEL
);
143 /* Initialize some spinlocks */
144 KeInitializeSpinLock(&KiFreezeExecutionLock
);
145 KeInitializeSpinLock(&Ki486CompatibilityLock
);
147 /* Initialize portable parts of the OS */
150 /* Initialize the Idle Process and the Process Listhead */
151 InitializeListHead(&KiProcessListHead
);
152 PageDirectory
.QuadPart
= 0;
153 KeInitializeProcess(InitProcess
,
158 InitProcess
->QuantumReset
= MAXCHAR
;
163 DPRINT1("SMP Boot support not yet present\n");
166 /* Initialize Kernel Memory Address Space */
167 MmInit1(FirstKrnlPhysAddr
,
170 (PADDRESS_RANGE
)&KeMemoryMap
,
171 KeMemoryMapRangeCount
,
174 /* Sets up the Text Sections of the Kernel and HAL for debugging */
177 /* Setup the Idle Thread */
178 KeInitializeThread(InitProcess
,
186 InitThread
->NextProcessor
= Number
;
187 InitThread
->Priority
= HIGH_PRIORITY
;
188 InitThread
->State
= Running
;
189 InitThread
->Affinity
= 1 << Number
;
190 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
191 InitProcess
->ActiveProcessors
= 1 << Number
;
193 /* HACK for MmUpdatePageDir */
194 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
196 /* Set up the thread-related fields in the PRCB */
197 Prcb
->CurrentThread
= InitThread
;
198 Prcb
->NextThread
= NULL
;
199 Prcb
->IdleThread
= InitThread
;
201 /* Initialize the Kernel Executive */
202 ExpInitializeExecutive(Number
, LoaderBlock
);
204 /* Only do this on the boot CPU */
207 /* Calculate the time reciprocal */
208 KiTimeIncrementReciprocal
=
209 KiComputeReciprocal(KeMaximumIncrement
,
210 &KiTimeIncrementShiftCount
);
212 /* Update DPC Values in case they got updated by the executive */
213 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
214 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
215 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
217 /* Allocate the DPC Stack */
218 DpcStack
= MmCreateKernelStack(FALSE
);
219 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
220 Prcb
->DpcStack
= DpcStack
;
222 /* Allocate the IOPM save area. */
223 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
225 TAG('K', 'e', ' ', ' '));
226 if (!Ki386IopmSaveArea
)
228 /* Bugcheck. We need this for V86/VDM support. */
229 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
233 /* Raise to Dispatch */
234 KfRaiseIrql(DISPATCH_LEVEL
);
236 /* Set the Idle Priority to 0. This will jump into Phase 1 */
237 KeSetPriorityThread(InitThread
, 0);
239 /* If there's no thread scheduled, put this CPU in the Idle summary */
240 if (!Prcb
->NextThread
) KiIdleSummary
|= 1 << Number
;
242 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */
243 KfRaiseIrql(HIGH_LEVEL
);
244 LoaderBlock
->Prcb
= 0;
249 KiGetMachineBootPointers(IN PKGDTENTRY
*Gdt
,
254 KDESCRIPTOR GdtDescriptor
, IdtDescriptor
;
255 KGDTENTRY TssSelector
, PcrSelector
;
258 /* Get GDT and IDT descriptors */
259 Ke386GetGlobalDescriptorTable(GdtDescriptor
);
260 Ke386GetInterruptDescriptorTable(IdtDescriptor
);
262 /* Save IDT and GDT */
263 *Gdt
= (PKGDTENTRY
)GdtDescriptor
.Base
;
264 *Idt
= (PKIDTENTRY
)IdtDescriptor
.Base
;
266 /* Get TSS and FS Selectors */
268 if (Tr
!= KGDT_TSS
) Tr
= KGDT_TSS
; // FIXME: HACKHACK
271 /* Get PCR Selector, mask it and get its GDT Entry */
272 PcrSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Fs
& ~RPL_MASK
));
274 /* Get the KPCR itself */
275 *Pcr
= (PKIPCR
)(ULONG_PTR
)(PcrSelector
.BaseLow
|
276 PcrSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
277 PcrSelector
.HighWord
.Bytes
.BaseHi
<< 24);
279 /* Get TSS Selector, mask it and get its GDT Entry */
280 TssSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Tr
& ~RPL_MASK
));
282 /* Get the KTSS itself */
283 *Tss
= (PKTSS
)(ULONG_PTR
)(TssSelector
.BaseLow
|
284 TssSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
285 TssSelector
.HighWord
.Bytes
.BaseHi
<< 24);
290 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
293 PKTHREAD InitialThread
;
300 /* Save the loader block and get the current CPU */
301 KeLoaderBlock
= LoaderBlock
;
302 Cpu
= KeNumberProcessors
;
305 /* If this is the boot CPU, set FS and the CPU Number*/
306 Ke386SetFs(KGDT_R0_PCR
);
307 __writefsdword(KPCR_PROCESSOR_NUMBER
, Cpu
);
309 /* Set the initial stack and idle thread as well */
310 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
311 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
314 /* Save the initial thread and stack */
315 InitialStack
= LoaderBlock
->KernelStack
;
316 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
318 /* Clean the APC List Head */
319 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
321 /* Initialize the machine type */
322 KiInitializeMachineType();
324 /* Skip initial setup if this isn't the Boot CPU */
325 if (Cpu
) goto AppCpuInit
;
327 /* Get GDT, IDT, PCR and TSS pointers */
328 KiGetMachineBootPointers(&Gdt
, &Idt
, &Pcr
, &Tss
);
330 /* Setup the TSS descriptors and entries */
331 Ki386InitializeTss(Tss
, Idt
, Gdt
);
333 /* Initialize the PCR */
334 RtlZeroMemory(Pcr
, PAGE_SIZE
);
343 /* Set us as the current process */
344 InitialThread
->ApcState
.Process
= &KiInitialProcess
.Pcb
;
346 /* Clear DR6/7 to cleanup bootloader debugging */
347 __writefsdword(KPCR_TEB
, 0);
348 __writefsdword(KPCR_DR6
, 0);
349 __writefsdword(KPCR_DR7
, 0);
351 /* Load Ring 3 selectors for DS/ES */
352 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
353 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
356 /* Loop until we can release the freeze lock */
359 /* Loop until execution can continue */
360 while ((volatile KSPIN_LOCK
)KiFreezeExecutionLock
== 1);
361 } while(InterlockedBitTestAndSet((PLONG
)&KiFreezeExecutionLock
, 0));
363 /* Setup CPU-related fields */
364 __writefsdword(KPCR_NUMBER
, Cpu
);
365 __writefsdword(KPCR_SET_MEMBER
, 1 << Cpu
);
366 __writefsdword(KPCR_SET_MEMBER_COPY
, 1 << Cpu
);
367 __writefsdword(KPCR_PRCB_SET_MEMBER
, 1 << Cpu
);
369 /* Initialize the Processor with HAL */
370 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
372 /* Set active processors */
373 KeActiveProcessors
|= __readfsdword(KPCR_SET_MEMBER
);
374 KeNumberProcessors
++;
376 /* Check if this is the boot CPU */
379 /* Initialize debugging system */
380 KdInitSystem(0, KeLoaderBlock
);
382 /* Check for break-in */
383 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
386 /* Raise to HIGH_LEVEL */
387 KfRaiseIrql(HIGH_LEVEL
);
389 /* Align stack and make space for the trap frame and NPX frame */
390 InitialStack
&= ~KTRAP_FRAME_ALIGN
;
391 __asm__
__volatile__("movl %0,%%esp" : :"r" (InitialStack
));
392 __asm__
__volatile__("subl %0,%%esp" : :"r" (NPX_FRAME_LENGTH
+
395 __asm__
__volatile__("push %0" : :"r" (CR0_EM
+ CR0_TS
+ CR0_MP
));
397 /* Call main kernel initialization */
398 KiInitializeKernel(&KiInitialProcess
.Pcb
,
401 (PKPRCB
)__readfsdword(KPCR_PRCB
),
405 /* Set the priority of this thread to 0 */
406 KeGetCurrentThread()->Priority
= 0;
408 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
410 KfLowerIrql(DISPATCH_LEVEL
);
412 /* Set the right wait IRQL */
413 KeGetCurrentThread()->WaitIrql
= DISPATCH_LEVEL
;
415 /* Set idle thread as running on UP builds */
417 KeGetCurrentThread()->State
= Running
;
420 /* Jump into the idle loop */