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 *****************************************************************/
16 /* GLOBALS *******************************************************************/
22 /* Spinlocks used only on X86 */
23 KSPIN_LOCK KiFreezeExecutionLock
;
24 KSPIN_LOCK Ki486CompatibilityLock
;
26 /* FUNCTIONS *****************************************************************/
30 KiInitializePcr(IN ULONG ProcessorNumber
,
35 IN PKTHREAD IdleThread
,
39 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
40 Pcr
->NtTib
.StackBase
= 0;
41 Pcr
->NtTib
.StackLimit
= 0;
44 /* Set the Current Thread */
45 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
47 /* Set pointers to ourselves */
48 Pcr
->Self
= (PKPCR
)Pcr
;
49 Pcr
->Prcb
= &Pcr
->PrcbData
;
51 /* Set the PCR Version */
52 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
53 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
55 /* Set the PCRB Version */
56 Pcr
->PrcbData
.MajorVersion
= 1;
57 Pcr
->PrcbData
.MinorVersion
= 1;
59 /* Set the Build Type */
60 Pcr
->PrcbData
.BuildType
= 0;
62 /* Set the Processor Number and current Processor Mask */
63 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
64 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
66 /* Set the PRCB for this Processor */
67 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
69 /* Start us out at PASSIVE_LEVEL */
70 Pcr
->Irql
= PASSIVE_LEVEL
;
72 /* Set the GDI, IDT, TSS and DPC Stack */
73 Pcr
->GDT
= (PVOID
)Gdt
;
76 Pcr
->PrcbData
.DpcStack
= DpcStack
;
81 KiInitializeKernel(IN PKPROCESS InitProcess
,
82 IN PKTHREAD InitThread
,
86 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
90 LARGE_INTEGER PageDirectory
;
93 /* Detect and set the CPU Type */
96 /* Set CR0 features based on detected CPU */
99 /* Check if an FPU is present */
100 NpxPresent
= KiIsNpxPresent();
102 /* Initialize the Power Management Support for this PRCB */
103 PoInitializePrcb(Prcb
);
105 /* Bugcheck if this is a 386 CPU */
106 if (Prcb
->CpuType
== 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
108 /* Get the processor features for the CPU */
109 FeatureBits
= KiGetFeatureBits();
111 /* Save feature bits */
112 Prcb
->FeatureBits
= FeatureBits
;
114 /* Get cache line information for this CPU */
115 KiGetCacheInformation();
117 /* Initialize spinlocks and DPC data */
118 KiInitSpinLocks(Prcb
, Number
);
120 /* Check if this is the Boot CPU */
124 KeNodeBlock
[0] = &KiNode0
;
125 Prcb
->ParentNode
= KeNodeBlock
[0];
126 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
128 /* Set boot-level flags */
129 KeI386NpxPresent
= NpxPresent
;
130 KeI386CpuType
= Prcb
->CpuType
;
131 KeI386CpuStep
= Prcb
->CpuStep
;
132 KeProcessorArchitecture
= 0;
133 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
134 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
135 KeFeatureBits
= FeatureBits
;
136 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
137 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
139 /* Set the current MP Master KPRCB to the Boot PRCB */
140 Prcb
->MultiThreadSetMaster
= Prcb
;
142 /* Lower to APC_LEVEL */
143 KfLowerIrql(APC_LEVEL
);
145 /* Initialize some spinlocks */
146 KeInitializeSpinLock(&KiFreezeExecutionLock
);
147 KeInitializeSpinLock(&Ki486CompatibilityLock
);
149 /* Initialize portable parts of the OS */
152 /* Initialize the Idle Process and the Process Listhead */
153 InitializeListHead(&KiProcessListHead
);
154 PageDirectory
.QuadPart
= 0;
155 KeInitializeProcess(InitProcess
,
160 InitProcess
->QuantumReset
= MAXCHAR
;
165 DPRINT1("SMP Boot support not yet present\n");
168 /* Setup the Idle Thread */
169 KeInitializeThread(InitProcess
,
177 InitThread
->NextProcessor
= Number
;
178 InitThread
->Priority
= HIGH_PRIORITY
;
179 InitThread
->State
= Running
;
180 InitThread
->Affinity
= 1 << Number
;
181 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
182 InitProcess
->ActiveProcessors
= 1 << Number
;
184 /* HACK for MmUpdatePageDir */
185 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
187 /* Set up the thread-related fields in the PRCB */
188 Prcb
->CurrentThread
= InitThread
;
189 Prcb
->NextThread
= NULL
;
190 Prcb
->IdleThread
= InitThread
;
192 /* Initialize the Kernel Executive */
193 ExpInitializeExecutive();
195 /* Only do this on the boot CPU */
198 /* Calculate the time reciprocal */
199 KiTimeIncrementReciprocal
=
200 KiComputeReciprocal(KeMaximumIncrement
,
201 &KiTimeIncrementShiftCount
);
203 /* Update DPC Values in case they got updated by the executive */
204 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
205 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
206 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
208 /* Allocate the DPC Stack */
209 DpcStack
= MmCreateKernelStack(FALSE
);
210 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
211 Prcb
->DpcStack
= DpcStack
;
213 /* Allocate the IOPM save area. */
214 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
216 TAG('K', 'e', ' ', ' '));
217 if (!Ki386IopmSaveArea
)
219 /* Bugcheck. We need this for V86/VDM support. */
220 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
224 /* Raise to Dispatch */
225 KfRaiseIrql(DISPATCH_LEVEL
);
227 /* Set the Idle Priority to 0. This will jump into Phase 1 */
228 KeSetPriorityThread(InitThread
, 0);
233 KiGetMachineBootPointers(IN PKGDTENTRY
*Gdt
,
238 KDESCRIPTOR GdtDescriptor
, IdtDescriptor
;
239 KGDTENTRY TssSelector
, PcrSelector
;
242 /* Get GDT and IDT descriptors */
243 Ke386GetGlobalDescriptorTable(GdtDescriptor
);
244 Ke386GetInterruptDescriptorTable(IdtDescriptor
);
246 /* Save IDT and GDT */
247 *Gdt
= (PKGDTENTRY
)GdtDescriptor
.Base
;
248 *Idt
= (PKIDTENTRY
)IdtDescriptor
.Base
;
250 /* Get TSS and FS Selectors */
252 if (Tr
!= KGDT_TSS
) Tr
= KGDT_TSS
; // FIXME: HACKHACK
255 /* Get PCR Selector, mask it and get its GDT Entry */
256 PcrSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Fs
& ~RPL_MASK
));
258 /* Get the KPCR itself */
259 *Pcr
= (PKIPCR
)(ULONG_PTR
)(PcrSelector
.BaseLow
|
260 PcrSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
261 PcrSelector
.HighWord
.Bytes
.BaseHi
<< 24);
263 /* Get TSS Selector, mask it and get its GDT Entry */
264 TssSelector
= *(PKGDTENTRY
)((ULONG_PTR
)*Gdt
+ (Tr
& ~RPL_MASK
));
266 /* Get the KTSS itself */
267 *Tss
= (PKTSS
)(ULONG_PTR
)(TssSelector
.BaseLow
|
268 TssSelector
.HighWord
.Bytes
.BaseMid
<< 16 |
269 TssSelector
.HighWord
.Bytes
.BaseHi
<< 24);
274 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
277 PKTHREAD InitialThread
;
284 /* Save the loader block and get the current CPU */
285 KeLoaderBlock
= LoaderBlock
;
286 Cpu
= KeNumberProcessors
;
289 /* If this is the boot CPU, set FS and the CPU Number*/
290 Ke386SetFs(KGDT_R0_PCR
);
291 KeGetPcr()->Number
= Cpu
;
293 /* Set the initial stack and idle thread as well */
294 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
295 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
298 /* Save the initial thread and stack */
299 InitialStack
= (PVOID
)LoaderBlock
->KernelStack
;
300 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
302 /* Clean the APC List Head */
303 InitializeListHead(&InitialThread
->ApcState
.ApcListHead
[KernelMode
]);
305 /* Initialize the machine type */
306 KiInitializeMachineType();
308 /* Skip initial setup if this isn't the Boot CPU */
309 if (Cpu
) goto AppCpuInit
;
311 /* Get GDT, IDT, PCR and TSS pointers */
312 KiGetMachineBootPointers(&Gdt
, &Idt
, &Pcr
, &Tss
);
314 /* Setup the TSS descriptors and entries */
315 Ki386InitializeTss(Tss
, Idt
);
317 /* Initialize the PCR */
318 RtlZeroMemory(Pcr
, PAGE_SIZE
);
327 /* Set us as the current process */
328 InitialThread
->ApcState
.Process
= &KiInitialProcess
.Pcb
;
330 /* Clear DR6/7 to cleanup bootloader debugging */
331 __writefsdword(KPCR_DR6
, 0);
332 __writefsdword(KPCR_DR7
, 0);
334 /* Load Ring 3 selectors for DS/ES */
335 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
336 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
339 /* Loop until we can release the freeze lock */
342 /* Loop until execution can continue */
343 while (KiFreezeExecutionLock
== 1);
344 } while(InterlockedBitTestAndSet(&KiFreezeExecutionLock
, 0));
346 /* Setup CPU-related fields */
347 __writefsdword(KPCR_NUMBER
, Cpu
);
348 __writefsdword(KPCR_SET_MEMBER
, 1 << Cpu
);
349 __writefsdword(KPCR_SET_MEMBER_COPY
, 1 << Cpu
);
350 __writefsdword(KPCR_PRCB_SET_MEMBER
, 1 << Cpu
);
352 /* Initialize the Processor with HAL */
353 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
355 /* Set active processors */
356 KeActiveProcessors
|= Pcr
->SetMember
;
357 KeNumberProcessors
++;
359 /* Check if this is the boot CPU */
362 /* Initialize debugging system */
363 KdInitSystem (0, KeLoaderBlock
);
365 /* Check for break-in */
366 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
369 /* Raise to HIGH_LEVEL */
370 KfRaiseIrql(HIGH_LEVEL
);
372 /* Call main kernel initialization */
373 KiInitializeKernel(&KiInitialProcess
.Pcb
,
376 &Pcr
->PrcbData
, //(PKPRCB)__readfsdword(KPCR_PRCB),
380 /* Set the priority of this thread to 0 */
381 KeGetCurrentThread()->Priority
= 0;
383 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */
385 KfLowerIrql(DISPATCH_LEVEL
);
387 /* Set the right wait IRQL */
388 KeGetCurrentThread()->WaitIrql
= DISPATCH_LEVEL
;
390 /* Set idle thread as running on UP builds */
392 KeGetCurrentThread()->State
= Running
;
395 /* Jump into the idle loop */