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
;
30 /* Boot and double-fault/NMI/DPC stack */
31 UCHAR
DECLSPEC_ALIGN(16) P0BootStackData
[KERNEL_STACK_SIZE
] = {0};
32 UCHAR
DECLSPEC_ALIGN(16) KiDoubleFaultStackData
[KERNEL_STACK_SIZE
] = {0};
33 ULONG_PTR P0BootStack
= (ULONG_PTR
)&P0BootStackData
[KERNEL_STACK_SIZE
];
34 ULONG_PTR KiDoubleFaultStack
= (ULONG_PTR
)&KiDoubleFaultStackData
[KERNEL_STACK_SIZE
];
36 /* FUNCTIONS *****************************************************************/
40 KiInitMachineDependent(VOID
)
42 /* Check for large page support */
43 if (KeFeatureBits
& KF_LARGE_PAGE
)
45 /* FIXME: Support this */
46 DPRINT("Large Page support detected but not yet taken advantage of!\n");
49 /* Check for global page support */
50 if (KeFeatureBits
& KF_GLOBAL_PAGE
)
52 /* FIXME: Support this */
53 DPRINT("Global Page support detected but not yet taken advantage of!\n");
56 /* Check if we have MTRR */
57 if (KeFeatureBits
& KF_MTRR
)
59 /* FIXME: Support this */
60 DPRINT("MTRR support detected but not yet taken advantage of!\n");
63 /* Check for PAT and/or MTRR support */
64 if (KeFeatureBits
& KF_PAT
)
66 /* FIXME: Support this */
67 DPRINT("PAT support detected but not yet taken advantage of!\n");
70 /* Allocate the IOPM save area. */
71 // Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
73 // TAG('K', 'e', ' ', ' '));
74 // if (!Ki386IopmSaveArea)
76 // /* Bugcheck. We need this for V86/VDM support. */
77 // KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
84 KiInitializePcr(IN PKIPCR Pcr
,
85 IN ULONG ProcessorNumber
,
86 IN PKTHREAD IdleThread
,
89 KDESCRIPTOR GdtDescriptor
= {{0},0,0}, IdtDescriptor
= {{0},0,0};
90 PKGDTENTRY64 TssEntry
;
93 /* Zero out the PCR */
94 RtlZeroMemory(Pcr
, PAGE_SIZE
);
96 /* Set pointers to ourselves */
97 Pcr
->Self
= (PKPCR
)Pcr
;
98 Pcr
->CurrentPrcb
= &Pcr
->Prcb
;
100 /* Set the PCR Version */
101 Pcr
->MajorVersion
= PCR_MAJOR_VERSION
;
102 Pcr
->MinorVersion
= PCR_MINOR_VERSION
;
104 /* Set the PRCB Version */
105 Pcr
->Prcb
.MajorVersion
= 1;
106 Pcr
->Prcb
.MinorVersion
= 1;
108 /* Set the Build Type */
109 Pcr
->Prcb
.BuildType
= 0;
111 Pcr
->Prcb
.BuildType
|= PRCB_BUILD_UNIPROCESSOR
;
114 Pcr
->Prcb
.BuildType
|= PRCB_BUILD_DEBUG
;
117 /* Set the Processor Number and current Processor Mask */
118 Pcr
->Prcb
.Number
= (UCHAR
)ProcessorNumber
;
119 Pcr
->Prcb
.SetMember
= 1ULL << ProcessorNumber
;
121 /* Get GDT and IDT descriptors */
122 __sgdt(&GdtDescriptor
.Limit
);
123 __sidt(&IdtDescriptor
.Limit
);
124 Pcr
->GdtBase
= (PVOID
)GdtDescriptor
.Base
;
125 Pcr
->IdtBase
= (PKIDTENTRY
)IdtDescriptor
.Base
;
127 /* Get TSS Selector */
129 ASSERT(Tr
== KGDT64_SYS_TSS
);
132 TssEntry
= KiGetGdtEntry(Pcr
->GdtBase
, Tr
);
134 /* Get the KTSS itself */
135 Pcr
->TssBase
= KiGetGdtDescriptorBase(TssEntry
);
137 Pcr
->Prcb
.RspBase
= Pcr
->TssBase
->Rsp0
; // FIXME
140 Pcr
->Prcb
.DpcStack
= DpcStack
;
142 /* Setup the processor set */
143 Pcr
->Prcb
.MultiThreadProcessorSet
= Pcr
->Prcb
.SetMember
;
145 /* Clear DR6/7 to cleanup bootloader debugging */
146 Pcr
->Prcb
.ProcessorState
.SpecialRegisters
.KernelDr6
= 0;
147 Pcr
->Prcb
.ProcessorState
.SpecialRegisters
.KernelDr7
= 0;
149 /* Set the Current Thread */
150 Pcr
->Prcb
.CurrentThread
= IdleThread
;
152 /* Start us out at PASSIVE_LEVEL */
153 Pcr
->Irql
= PASSIVE_LEVEL
;
154 KeSetCurrentIrql(PASSIVE_LEVEL
);
157 __writemsr(X86_MSR_GSBASE
, (ULONG64
)Pcr
);
158 __writemsr(X86_MSR_KERNEL_GSBASE
, (ULONG64
)Pcr
);
163 KiInitializeCpu(PKPRCB Prcb
)
167 /* Detect and set the CPU Type */
168 KiSetProcessorType();
170 /* Get the processor features for this CPU */
171 FeatureBits
= KiGetFeatureBits();
173 /* Check if we support all needed features */
174 if ((FeatureBits
& REQUIRED_FEATURE_BITS
) != REQUIRED_FEATURE_BITS
)
176 /* If not, bugcheck system */
177 FrLdrDbgPrint("CPU doesn't have needed features! Has: 0x%x, required: 0x%x\n",
178 FeatureBits
, REQUIRED_FEATURE_BITS
);
182 /* Set DEP to always on */
183 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSON
;
184 FeatureBits
|= KF_NX_ENABLED
;
186 /* Save feature bits */
187 Prcb
->FeatureBits
= FeatureBits
;
189 /* Enable fx save restore support */
190 __writecr4(__readcr4() | CR4_FXSR
);
192 /* Enable XMMI exceptions */
193 __writecr4(__readcr4() | CR4_XMMEXCPT
);
195 /* Enable Write-Protection */
196 __writecr0(__readcr0() | CR0_WP
);
198 /* Disable fpu monitoring */
199 __writecr0(__readcr0() & ~CR0_MP
);
201 /* Disable x87 fpu exceptions */
202 __writecr0(__readcr0() & ~CR0_NE
);
210 KiInitializeTss(IN PKTSS64 Tss
,
213 PKGDTENTRY64 TssEntry
;
215 /* Get pointer to the GDT entry */
216 TssEntry
= KiGetGdtEntry(KeGetPcr()->GdtBase
, KGDT64_SYS_TSS
);
218 /* Initialize the GDT entry */
219 KiInitGdtEntry(TssEntry
, (ULONG64
)Tss
, sizeof(KTSS64
), AMD64_TSS
, 0);
221 /* Zero out the TSS */
222 RtlZeroMemory(Tss
, sizeof(KTSS64
));
224 /* FIXME: I/O Map? */
225 Tss
->IoMapBase
= 0x68;
227 /* Setup ring 0 stack pointer */
230 /* Setup a stack for Double Fault Traps */
231 Tss
->Ist
[1] = (ULONG64
)KiDoubleFaultStack
;
233 /* Setup a stack for CheckAbort Traps */
234 Tss
->Ist
[2] = (ULONG64
)KiDoubleFaultStack
;
236 /* Setup a stack for NMI Traps */
237 Tss
->Ist
[3] = (ULONG64
)KiDoubleFaultStack
;
239 /* Load the task register */
240 __ltr(KGDT64_SYS_TSS
);
246 KiInitializeKernelMachineDependent(
248 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
250 /* Set boot-level flags */
251 KeI386CpuType
= Prcb
->CpuType
;
252 KeI386CpuStep
= Prcb
->CpuStep
;
253 KeProcessorArchitecture
= PROCESSOR_ARCHITECTURE_AMD64
;
254 KeProcessorLevel
= (USHORT
)Prcb
->CpuType
;
255 if (Prcb
->CpuID
) KeProcessorRevision
= Prcb
->CpuStep
;
257 /* Set basic CPU Features that user mode can read */
258 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
259 (Prcb
->FeatureBits
& KF_MMX
) ? TRUE
: FALSE
;
260 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] = TRUE
;
261 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
262 ((Prcb
->FeatureBits
& KF_FXSR
) && (Prcb
->FeatureBits
& KF_XMMI
)) ? TRUE
: FALSE
;
263 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
264 ((Prcb
->FeatureBits
& KF_FXSR
) && (Prcb
->FeatureBits
& KF_XMMI64
)) ? TRUE
: FALSE
;
265 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
266 (Prcb
->FeatureBits
& KF_3DNOW
) ? TRUE
: FALSE
;
267 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] = TRUE
;
269 /* Set the default NX policy (opt-in) */
270 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTIN
;
272 /* Check if NPX is always on */
273 if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSON"))
275 /* Set it always on */
276 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSON
;
277 Prcb
->FeatureBits
|= KF_NX_ENABLED
;
279 else if (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTOUT"))
281 /* Set it in opt-out mode */
282 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_OPTOUT
;
283 Prcb
->FeatureBits
|= KF_NX_ENABLED
;
285 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=OPTIN")) ||
286 (strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE")))
288 /* Set the feature bits */
289 Prcb
->FeatureBits
|= KF_NX_ENABLED
;
291 else if ((strstr(KeLoaderBlock
->LoadOptions
, "NOEXECUTE=ALWAYSOFF")) ||
292 (strstr(KeLoaderBlock
->LoadOptions
, "EXECUTE")))
294 /* Set disabled mode */
295 SharedUserData
->NXSupportPolicy
= NX_SUPPORT_POLICY_ALWAYSOFF
;
296 Prcb
->FeatureBits
|= KF_NX_DISABLED
;
301 static LDR_DATA_TABLE_ENTRY LdrCoreEntries
[3];
304 KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
306 PLDR_DATA_TABLE_ENTRY LdrEntry
;
310 /* Initialize the list head */
311 InitializeListHead(&PsLoadedModuleList
);
313 /* Loop the first 3 entries */
314 for (Entry
= LoaderBlock
->LoadOrderListHead
.Flink
, i
= 0;
315 Entry
!= &LoaderBlock
->LoadOrderListHead
&& i
< 3;
316 Entry
= Entry
->Flink
, i
++)
318 /* Get the data table entry */
319 LdrEntry
= CONTAINING_RECORD(Entry
,
320 LDR_DATA_TABLE_ENTRY
,
324 LdrCoreEntries
[i
] = *LdrEntry
;
326 /* Insert the copy into the list */
327 InsertTailList(&PsLoadedModuleList
, &LdrCoreEntries
[i
].InLoadOrderLinks
);
333 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
336 PKTHREAD InitialThread
;
337 ULONG64 InitialStack
;
341 FrLdrDbgPrint
= LoaderBlock
->u
.I386
.CommonDataArea
;
342 FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
344 /* Save the loader block */
345 KeLoaderBlock
= LoaderBlock
;
347 /* Get the current CPU number */
348 Cpu
= (CCHAR
)KeNumberProcessors
++; // FIXME
350 /* LoaderBlock initialization for Cpu 0 */
353 FrLdrDbgPrint("LoaderBlock->Prcb=%p\n", LoaderBlock
->Prcb
);
354 /* Set the initial stack, idle thread and process */
355 LoaderBlock
->KernelStack
= (ULONG_PTR
)P0BootStack
;
356 LoaderBlock
->Thread
= (ULONG_PTR
)&KiInitialThread
;
357 LoaderBlock
->Process
= (ULONG_PTR
)&KiInitialProcess
.Pcb
;
358 LoaderBlock
->Prcb
= (ULONG_PTR
)&KiInitialPcr
.Prcb
;
361 /* Get Pcr from loader block */
362 Pcr
= CONTAINING_RECORD(LoaderBlock
->Prcb
, KIPCR
, Prcb
);
364 /* Set the PRCB for this Processor */
365 KiProcessorBlock
[Cpu
] = &Pcr
->Prcb
;
367 /* Align stack to 16 bytes */
368 LoaderBlock
->KernelStack
&= ~(16 - 1);
370 /* Save the initial thread and stack */
371 InitialStack
= LoaderBlock
->KernelStack
; // Checkme
372 InitialThread
= (PKTHREAD
)LoaderBlock
->Thread
;
374 /* Set us as the current process */
375 InitialThread
->ApcState
.Process
= (PVOID
)LoaderBlock
->Process
;
377 /* Initialize the PCR */
378 KiInitializePcr(Pcr
, Cpu
, InitialThread
, (PVOID
)KiDoubleFaultStack
);
380 /* Initialize the CPU features */
381 KiInitializeCpu(&Pcr
->Prcb
);
383 /* Initial setup for the boot CPU */
386 /* Initialize the module list (ntos, hal, kdcom) */
387 KiInitModuleList(LoaderBlock
);
389 /* Setup the TSS descriptors and entries */
390 KiInitializeTss(Pcr
->TssBase
, InitialStack
);
395 /* Initialize debugging system */
396 KdInitSystem(0, KeLoaderBlock
);
398 /* Check for break-in */
399 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
402 DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
403 Pcr
, Pcr
->GdtBase
, Pcr
->IdtBase
, Pcr
->TssBase
);
406 while (InterlockedBitTestAndSet64((PLONG64
)&KiFreezeExecutionLock
, 0))
408 /* Loop until lock is free */
409 while ((*(volatile KSPIN_LOCK
*)&KiFreezeExecutionLock
) & 1);
412 /* Initialize the Processor with HAL */
413 HalInitializeProcessor(Cpu
, KeLoaderBlock
);
415 /* Set processor as active */
416 KeActiveProcessors
|= 1ULL << Cpu
;
419 InterlockedAnd64((PLONG64
)&KiFreezeExecutionLock
, 0);
421 /* Raise to HIGH_LEVEL */
422 KfRaiseIrql(HIGH_LEVEL
);
424 /* Machine specific kernel initialization */
425 if (Cpu
== 0) KiInitializeKernelMachineDependent(&Pcr
->Prcb
, LoaderBlock
);
427 /* Switch to new kernel stack and start kernel bootstrapping */
428 KiSwitchToBootStack(InitialStack
& ~3);