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 *******************************************************************/
21 /* Spinlocks used only on X86 */
22 KSPIN_LOCK KiFreezeExecutionLock
;
23 KSPIN_LOCK Ki486CompatibilityLock
;
25 /* FUNCTIONS *****************************************************************/
29 KiInitializePcr(IN ULONG ProcessorNumber
,
34 IN PKTHREAD IdleThread
,
38 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
39 Pcr
->NtTib
.StackBase
= 0;
40 Pcr
->NtTib
.StackLimit
= 0;
43 /* Set the Current Thread */
44 Pcr
->PrcbData
.CurrentThread
= IdleThread
;
46 /* Set pointers to ourselves */
47 Pcr
->Self
= (PKPCR
)Pcr
;
48 Pcr
->Prcb
= &Pcr
->PrcbData
;
50 /* Set the PCR Version */
51 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
52 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
54 /* Set the PCRB Version */
55 Pcr
->PrcbData
.MajorVersion
= 1;
56 Pcr
->PrcbData
.MinorVersion
= 1;
58 /* Set the Build Type */
59 Pcr
->PrcbData
.BuildType
= 0;
61 /* Set the Processor Number and current Processor Mask */
62 Pcr
->PrcbData
.Number
= (UCHAR
)ProcessorNumber
;
63 Pcr
->PrcbData
.SetMember
= 1 << ProcessorNumber
;
65 /* Set the PRCB for this Processor */
66 KiProcessorBlock
[ProcessorNumber
] = Pcr
->Prcb
;
68 /* Start us out at PASSIVE_LEVEL */
69 Pcr
->Irql
= PASSIVE_LEVEL
;
71 /* Set the GDI, IDT, TSS and DPC Stack */
72 Pcr
->GDT
= (PVOID
)Gdt
;
75 Pcr
->PrcbData
.DpcStack
= DpcStack
;
80 KiInitializeKernel(IN PKPROCESS InitProcess
,
81 IN PKTHREAD InitThread
,
85 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
89 LARGE_INTEGER PageDirectory
;
92 /* Detect and set the CPU Type */
95 /* Set CR0 features based on detected CPU */
98 /* Check if an FPU is present */
99 NpxPresent
= KiIsNpxPresent();
101 /* Initialize the Power Management Support for this PRCB */
102 PoInitializePrcb(Prcb
);
104 /* Bugcheck if this is a 386 CPU */
105 if (Prcb
->CpuType
== 3) KeBugCheckEx(0x5D, 0x386, 0, 0, 0);
107 /* Get the processor features for the CPU */
108 FeatureBits
= KiGetFeatureBits();
110 /* Save feature bits */
111 Prcb
->FeatureBits
= FeatureBits
;
113 /* Get cache line information for this CPU */
114 KiGetCacheInformation();
116 /* Initialize spinlocks and DPC data */
117 KiInitSpinLocks(Prcb
, Number
);
119 /* Check if this is the Boot CPU */
123 KeNodeBlock
[0] = &KiNode0
;
124 Prcb
->ParentNode
= KeNodeBlock
[0];
125 KeNodeBlock
[0]->ProcessorMask
= Prcb
->SetMember
;
127 /* Set boot-level flags */
128 KeI386NpxPresent
= NpxPresent
;
129 KeI386CpuType
= Prcb
->CpuType
;
130 KeI386CpuStep
= Prcb
->CpuStep
;
131 KeProcessorArchitecture
= 0;
132 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
133 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
134 KeFeatureBits
= FeatureBits
;
135 KeI386FxsrPresent
= (KeFeatureBits
& KF_FXSR
) ? TRUE
: FALSE
;
136 KeI386XMMIPresent
= (KeFeatureBits
& KF_XMMI
) ? TRUE
: FALSE
;
138 /* Set the current MP Master KPRCB to the Boot PRCB */
139 Prcb
->MultiThreadSetMaster
= Prcb
;
141 /* Lower to APC_LEVEL */
142 KfLowerIrql(APC_LEVEL
);
144 /* Initialize some spinlocks */
145 KeInitializeSpinLock(&KiFreezeExecutionLock
);
146 KeInitializeSpinLock(&Ki486CompatibilityLock
);
148 /* Initialize portable parts of the OS */
151 /* Initialize the Idle Process and the Process Listhead */
152 InitializeListHead(&KiProcessListHead
);
153 PageDirectory
.QuadPart
= 0;
154 KeInitializeProcess(InitProcess
,
159 InitProcess
->QuantumReset
= MAXCHAR
;
164 DPRINT1("SMP Boot support not yet present\n");
167 /* Setup the Idle Thread */
168 KeInitializeThread(InitProcess
,
176 InitThread
->NextProcessor
= Number
;
177 InitThread
->Priority
= HIGH_PRIORITY
;
178 InitThread
->State
= Running
;
179 InitThread
->Affinity
= 1 << Number
;
180 InitThread
->WaitIrql
= DISPATCH_LEVEL
;
181 InitProcess
->ActiveProcessors
= 1 << Number
;
183 /* HACK for MmUpdatePageDir */
184 ((PETHREAD
)InitThread
)->ThreadsProcess
= (PEPROCESS
)InitProcess
;
186 /* Set up the thread-related fields in the PRCB */
187 Prcb
->CurrentThread
= InitThread
;
188 Prcb
->NextThread
= NULL
;
189 Prcb
->IdleThread
= InitThread
;
191 /* Initialize the Kernel Executive */
192 ExpInitializeExecutive();
194 /* Only do this on the boot CPU */
197 /* Calculate the time reciprocal */
198 KiTimeIncrementReciprocal
=
199 KiComputeReciprocal(KeMaximumIncrement
,
200 &KiTimeIncrementShiftCount
);
202 /* Update DPC Values in case they got updated by the executive */
203 Prcb
->MaximumDpcQueueDepth
= KiMaximumDpcQueueDepth
;
204 Prcb
->MinimumDpcRate
= KiMinimumDpcRate
;
205 Prcb
->AdjustDpcThreshold
= KiAdjustDpcThreshold
;
207 /* Allocate the DPC Stack */
208 DpcStack
= MmCreateKernelStack(FALSE
);
209 if (!DpcStack
) KeBugCheckEx(NO_PAGES_AVAILABLE
, 1, 0, 0, 0);
210 Prcb
->DpcStack
= DpcStack
;
212 /* Allocate the IOPM save area. */
213 Ki386IopmSaveArea
= ExAllocatePoolWithTag(PagedPool
,
215 TAG('K', 'e', ' ', ' '));
216 if (!Ki386IopmSaveArea
)
218 /* Bugcheck. We need this for V86/VDM support. */
219 KeBugCheckEx(NO_PAGES_AVAILABLE
, 2, PAGE_SIZE
* 2, 0, 0);
223 /* Raise to Dispatch */
224 KfRaiseIrql(DISPATCH_LEVEL
);
226 /* Set the Idle Priority to 0. This will jump into Phase 1 */
227 KeSetPriorityThread(InitThread
, 0);
232 KiSystemStartup(IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
235 PKIPCR Pcr
= (PKIPCR
)KPCR_BASE
;
238 /* Save the loader block and get the current CPU */
239 //KeLoaderBlock = LoaderBlock;
240 Cpu
= KeNumberProcessors
;
243 /* If this is the boot CPU, set FS and the CPU Number*/
244 Ke386SetFs(KGDT_R0_PCR
);
245 KeGetPcr()->Number
= Cpu
;
248 /* Skip initial setup if this isn't the Boot CPU */
249 if (Cpu
) goto AppCpuInit
;
251 /* Setup the boot (Freeldr should've done), double fault and NMI TSS */
252 Ki386InitializeTss();
254 /* Initialize the PCR */
255 RtlZeroMemory(Pcr
, PAGE_SIZE
);
261 &KiInitialThread
.Tcb
,
264 /* Set us as the current process */
265 KiInitialThread
.Tcb
.ApcState
.Process
= &KiInitialProcess
.Pcb
;
267 /* Clear DR6/7 to cleanup bootloader debugging */
268 Pcr
->PrcbData
.ProcessorState
.SpecialRegisters
.KernelDr6
= 0;
269 Pcr
->PrcbData
.ProcessorState
.SpecialRegisters
.KernelDr7
= 0;
271 /* Load Ring 3 selectors for DS/ES */
272 Ke386SetDs(KGDT_R3_DATA
| RPL_MASK
);
273 Ke386SetEs(KGDT_R3_DATA
| RPL_MASK
);
275 /* Setup CPU-related fields */
279 Pcr
->SetMember
= 1 << Cpu
;
280 Pcr
->SetMemberCopy
= 1 << Cpu
;
281 Prcb
->SetMember
= 1 << Cpu
;
283 /* Initialize the Processor with HAL */
284 HalInitializeProcessor(Cpu
, (PLOADER_PARAMETER_BLOCK
)&KeLoaderBlock
);
286 /* Set active processors */
287 KeActiveProcessors
|= Pcr
->SetMember
;
288 KeNumberProcessors
++;
290 /* Initialize the Debugger for the Boot CPU */
291 if (!Cpu
) KdInitSystem (0, &KeLoaderBlock
);
293 /* Check for break-in */
294 if (KdPollBreakIn()) DbgBreakPointWithStatus(1);
296 /* Raise to HIGH_LEVEL */
297 KfRaiseIrql(HIGH_LEVEL
);
299 /* Call main kernel intialization */
300 KiInitializeKernel(&KiInitialProcess
.Pcb
,
301 &KiInitialThread
.Tcb
,
307 /* Lower IRQL back to DISPATCH_LEVEL */
308 KfLowerIrql(DISPATCH_LEVEL
);
310 /* Set the priority of this thread to 0 */
311 KeGetCurrentThread()->Priority
= 0;
313 /* Jump into the idle loop */