[CLT2012]
[reactos.git] / ntoskrnl / ke / amd64 / kiinit.c
1 /*
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define REQUIRED_FEATURE_BITS (KF_RDTSC|KF_CR4|KF_CMPXCHG8B|KF_XMMI|KF_XMMI64| \
17 KF_NX_BIT)
18
19 /* GLOBALS *******************************************************************/
20
21 /* Function pointer for early debug prints */
22 ULONG (*FrLdrDbgPrint)(const char *Format, ...);
23
24 /* Spinlocks used only on X86 */
25 KSPIN_LOCK KiFreezeExecutionLock;
26
27
28 KIPCR KiInitialPcr;
29
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];
35
36 /* FUNCTIONS *****************************************************************/
37
38 VOID
39 NTAPI
40 KiInitMachineDependent(VOID)
41 {
42 /* Check for large page support */
43 if (KeFeatureBits & KF_LARGE_PAGE)
44 {
45 /* FIXME: Support this */
46 DPRINT("Large Page support detected but not yet taken advantage of!\n");
47 }
48
49 /* Check for global page support */
50 if (KeFeatureBits & KF_GLOBAL_PAGE)
51 {
52 /* FIXME: Support this */
53 DPRINT("Global Page support detected but not yet taken advantage of!\n");
54 }
55
56 /* Check if we have MTRR */
57 if (KeFeatureBits & KF_MTRR)
58 {
59 /* FIXME: Support this */
60 DPRINT("MTRR support detected but not yet taken advantage of!\n");
61 }
62
63 /* Check for PAT and/or MTRR support */
64 if (KeFeatureBits & KF_PAT)
65 {
66 /* FIXME: Support this */
67 DPRINT("PAT support detected but not yet taken advantage of!\n");
68 }
69
70 /* Allocate the IOPM save area. */
71 // Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,
72 // PAGE_SIZE * 2,
73 // TAG('K', 'e', ' ', ' '));
74 // if (!Ki386IopmSaveArea)
75 // {
76 // /* Bugcheck. We need this for V86/VDM support. */
77 // KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);
78 // }
79
80 }
81
82 VOID
83 NTAPI
84 KiInitializePcr(IN PKIPCR Pcr,
85 IN ULONG ProcessorNumber,
86 IN PKTHREAD IdleThread,
87 IN PVOID DpcStack)
88 {
89 KDESCRIPTOR GdtDescriptor = {{0},0,0}, IdtDescriptor = {{0},0,0};
90 PKGDTENTRY64 TssEntry;
91 USHORT Tr = 0;
92
93 /* Zero out the PCR */
94 RtlZeroMemory(Pcr, PAGE_SIZE);
95
96 /* Set pointers to ourselves */
97 Pcr->Self = (PKPCR)Pcr;
98 Pcr->CurrentPrcb = &Pcr->Prcb;
99
100 /* Set the PCR Version */
101 Pcr->MajorVersion = PCR_MAJOR_VERSION;
102 Pcr->MinorVersion = PCR_MINOR_VERSION;
103
104 /* Set the PRCB Version */
105 Pcr->Prcb.MajorVersion = 1;
106 Pcr->Prcb.MinorVersion = 1;
107
108 /* Set the Build Type */
109 Pcr->Prcb.BuildType = 0;
110 #ifndef CONFIG_SMP
111 Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR;
112 #endif
113 #ifdef DBG
114 Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG;
115 #endif
116
117 /* Set the Processor Number and current Processor Mask */
118 Pcr->Prcb.Number = (UCHAR)ProcessorNumber;
119 Pcr->Prcb.SetMember = 1ULL << ProcessorNumber;
120
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;
126
127 /* Get TSS Selector */
128 __str(&Tr);
129 ASSERT(Tr == KGDT64_SYS_TSS);
130
131 /* Get TSS Entry */
132 TssEntry = KiGetGdtEntry(Pcr->GdtBase, Tr);
133
134 /* Get the KTSS itself */
135 Pcr->TssBase = KiGetGdtDescriptorBase(TssEntry);
136
137 Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; // FIXME
138
139 /* Set DPC Stack */
140 Pcr->Prcb.DpcStack = DpcStack;
141
142 /* Setup the processor set */
143 Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember;
144
145 /* Clear DR6/7 to cleanup bootloader debugging */
146 Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr6 = 0;
147 Pcr->Prcb.ProcessorState.SpecialRegisters.KernelDr7 = 0;
148
149 /* Set the Current Thread */
150 Pcr->Prcb.CurrentThread = IdleThread;
151
152 /* Start us out at PASSIVE_LEVEL */
153 Pcr->Irql = PASSIVE_LEVEL;
154 KeSetCurrentIrql(PASSIVE_LEVEL);
155
156 /* Set GS base */
157 __writemsr(X86_MSR_GSBASE, (ULONG64)Pcr);
158 __writemsr(X86_MSR_KERNEL_GSBASE, (ULONG64)Pcr);
159 }
160
161 VOID
162 NTAPI
163 KiInitializeCpu(PKPRCB Prcb)
164 {
165 ULONG FeatureBits;
166
167 /* Detect and set the CPU Type */
168 KiSetProcessorType();
169
170 /* Get the processor features for this CPU */
171 FeatureBits = KiGetFeatureBits();
172
173 /* Check if we support all needed features */
174 if ((FeatureBits & REQUIRED_FEATURE_BITS) != REQUIRED_FEATURE_BITS)
175 {
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);
179 KeBugCheck(0);
180 }
181
182 /* Set DEP to always on */
183 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
184 FeatureBits |= KF_NX_ENABLED;
185
186 /* Save feature bits */
187 Prcb->FeatureBits = FeatureBits;
188
189 /* Enable fx save restore support */
190 __writecr4(__readcr4() | CR4_FXSR);
191
192 /* Enable XMMI exceptions */
193 __writecr4(__readcr4() | CR4_XMMEXCPT);
194
195 /* Enable Write-Protection */
196 __writecr0(__readcr0() | CR0_WP);
197
198 /* Disable fpu monitoring */
199 __writecr0(__readcr0() & ~CR0_MP);
200
201 /* Disable x87 fpu exceptions */
202 __writecr0(__readcr0() & ~CR0_NE);
203
204 /* LDT is unused */
205 __lldt(0);
206 }
207
208 VOID
209 FASTCALL
210 KiInitializeTss(IN PKTSS64 Tss,
211 IN UINT64 Stack)
212 {
213 PKGDTENTRY64 TssEntry;
214
215 /* Get pointer to the GDT entry */
216 TssEntry = KiGetGdtEntry(KeGetPcr()->GdtBase, KGDT64_SYS_TSS);
217
218 /* Initialize the GDT entry */
219 KiInitGdtEntry(TssEntry, (ULONG64)Tss, sizeof(KTSS64), AMD64_TSS, 0);
220
221 /* Zero out the TSS */
222 RtlZeroMemory(Tss, sizeof(KTSS64));
223
224 /* FIXME: I/O Map? */
225 Tss->IoMapBase = 0x68;
226
227 /* Setup ring 0 stack pointer */
228 Tss->Rsp0 = Stack;
229
230 /* Setup a stack for Double Fault Traps */
231 Tss->Ist[1] = (ULONG64)KiDoubleFaultStack;
232
233 /* Setup a stack for CheckAbort Traps */
234 Tss->Ist[2] = (ULONG64)KiDoubleFaultStack;
235
236 /* Setup a stack for NMI Traps */
237 Tss->Ist[3] = (ULONG64)KiDoubleFaultStack;
238
239 /* Load the task register */
240 __ltr(KGDT64_SYS_TSS);
241 }
242
243 VOID
244 NTAPI
245 INIT_FUNCTION
246 KiInitializeKernelMachineDependent(
247 IN PKPRCB Prcb,
248 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
249 {
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;
256
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;
268
269 /* Set the default NX policy (opt-in) */
270 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN;
271
272 /* Check if NPX is always on */
273 if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSON"))
274 {
275 /* Set it always on */
276 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSON;
277 Prcb->FeatureBits |= KF_NX_ENABLED;
278 }
279 else if (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTOUT"))
280 {
281 /* Set it in opt-out mode */
282 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTOUT;
283 Prcb->FeatureBits |= KF_NX_ENABLED;
284 }
285 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=OPTIN")) ||
286 (strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE")))
287 {
288 /* Set the feature bits */
289 Prcb->FeatureBits |= KF_NX_ENABLED;
290 }
291 else if ((strstr(KeLoaderBlock->LoadOptions, "NOEXECUTE=ALWAYSOFF")) ||
292 (strstr(KeLoaderBlock->LoadOptions, "EXECUTE")))
293 {
294 /* Set disabled mode */
295 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_ALWAYSOFF;
296 Prcb->FeatureBits |= KF_NX_DISABLED;
297 }
298
299 }
300
301 static LDR_DATA_TABLE_ENTRY LdrCoreEntries[3];
302
303 void
304 KiInitModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
305 {
306 PLDR_DATA_TABLE_ENTRY LdrEntry;
307 PLIST_ENTRY Entry;
308 ULONG i;
309
310 /* Initialize the list head */
311 InitializeListHead(&PsLoadedModuleList);
312
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++)
317 {
318 /* Get the data table entry */
319 LdrEntry = CONTAINING_RECORD(Entry,
320 LDR_DATA_TABLE_ENTRY,
321 InLoadOrderLinks);
322
323 /* Copy the entry */
324 LdrCoreEntries[i] = *LdrEntry;
325
326 /* Insert the copy into the list */
327 InsertTailList(&PsLoadedModuleList, &LdrCoreEntries[i].InLoadOrderLinks);
328 }
329 }
330
331 VOID
332 NTAPI
333 KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
334 {
335 CCHAR Cpu;
336 PKTHREAD InitialThread;
337 ULONG64 InitialStack;
338 PKIPCR Pcr;
339
340 /* HACK */
341 FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea;
342 FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
343
344 /* Save the loader block */
345 KeLoaderBlock = LoaderBlock;
346
347 /* Get the current CPU number */
348 Cpu = (CCHAR)KeNumberProcessors++; // FIXME
349
350 /* LoaderBlock initialization for Cpu 0 */
351 if (Cpu == 0)
352 {
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;
359 }
360
361 /* Get Pcr from loader block */
362 Pcr = CONTAINING_RECORD(LoaderBlock->Prcb, KIPCR, Prcb);
363
364 /* Set the PRCB for this Processor */
365 KiProcessorBlock[Cpu] = &Pcr->Prcb;
366
367 /* Align stack to 16 bytes */
368 LoaderBlock->KernelStack &= ~(16 - 1);
369
370 /* Save the initial thread and stack */
371 InitialStack = LoaderBlock->KernelStack; // Checkme
372 InitialThread = (PKTHREAD)LoaderBlock->Thread;
373
374 /* Set us as the current process */
375 InitialThread->ApcState.Process = (PVOID)LoaderBlock->Process;
376
377 /* Initialize the PCR */
378 KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack);
379
380 /* Initialize the CPU features */
381 KiInitializeCpu(&Pcr->Prcb);
382
383 /* Initial setup for the boot CPU */
384 if (Cpu == 0)
385 {
386 /* Initialize the module list (ntos, hal, kdcom) */
387 KiInitModuleList(LoaderBlock);
388
389 /* Setup the TSS descriptors and entries */
390 KiInitializeTss(Pcr->TssBase, InitialStack);
391
392 /* Setup the IDT */
393 KeInitExceptions();
394
395 /* Initialize debugging system */
396 KdInitSystem(0, KeLoaderBlock);
397
398 /* Check for break-in */
399 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
400 }
401
402 DPRINT1("Pcr = %p, Gdt = %p, Idt = %p, Tss = %p\n",
403 Pcr, Pcr->GdtBase, Pcr->IdtBase, Pcr->TssBase);
404
405 /* Acquire lock */
406 while (InterlockedBitTestAndSet64((PLONG64)&KiFreezeExecutionLock, 0))
407 {
408 /* Loop until lock is free */
409 while ((*(volatile KSPIN_LOCK*)&KiFreezeExecutionLock) & 1);
410 }
411
412 /* Initialize the Processor with HAL */
413 HalInitializeProcessor(Cpu, KeLoaderBlock);
414
415 /* Set processor as active */
416 KeActiveProcessors |= 1ULL << Cpu;
417
418 /* Release lock */
419 InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0);
420
421 /* Raise to HIGH_LEVEL */
422 KfRaiseIrql(HIGH_LEVEL);
423
424 /* Machine specific kernel initialization */
425 if (Cpu == 0) KiInitializeKernelMachineDependent(&Pcr->Prcb, LoaderBlock);
426
427 /* Switch to new kernel stack and start kernel bootstrapping */
428 KiSwitchToBootStack(InitialStack & ~3);
429 }
430