Standardize comment headers. Patch by Trevor McCort
[reactos.git] / reactos / ntoskrnl / ke / i386 / kernel.c
1 /* $Id:$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/kernel.c
6 * PURPOSE: Initializes the kernel
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 ULONG KiPcrInitDone = 0;
20 static ULONG PcrsAllocated = 0;
21 static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags;
22 ULONG Ke386CacheAlignment;
23 CHAR Ke386CpuidModel[49] = {0,};
24 ULONG Ke386L1CacheSize;
25 BOOLEAN Ke386NoExecute = FALSE;
26 BOOLEAN Ke386Pae = FALSE;
27 BOOLEAN Ke386PaeEnabled = FALSE;
28 BOOLEAN Ke386GlobalPagesEnabled = FALSE;
29 ULONG KiFastSystemCallDisable = 1;
30
31 /* FUNCTIONS *****************************************************************/
32
33 VOID INIT_FUNCTION STATIC
34 Ki386GetCpuId(VOID)
35 {
36 ULONG OrigFlags, Flags, FinalFlags;
37 ULONG MaxCpuidLevel;
38 ULONG Dummy, Eax, Ebx, Ecx, Edx;
39 PKPCR Pcr = KeGetCurrentKPCR();
40
41 Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
42 Ke386CacheAlignment = 32;
43
44 /* Try to toggle the id bit in eflags. */
45 Ke386SaveFlags(OrigFlags);
46 Flags = OrigFlags ^ X86_EFLAGS_ID;
47 Ke386RestoreFlags(Flags);
48 Ke386SaveFlags(FinalFlags);
49 if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
50 {
51 /* No cpuid supported. */
52 Pcr->PrcbData.CpuID = FALSE;
53 Pcr->PrcbData.CpuType = 3;
54 return;
55 }
56 Pcr->PrcbData.CpuID = TRUE;
57
58 /* Get the vendor name and the maximum cpuid level supported. */
59 Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Pcr->PrcbData.VendorString[0], (PULONG)&Pcr->PrcbData.VendorString[8], (PULONG)&Pcr->PrcbData.VendorString[4]);
60 if (MaxCpuidLevel > 0)
61 {
62 /* Get the feature flags. */
63 Ki386Cpuid(1, &Eax, &Ebx, &Ke386CpuidFlags2, &Pcr->PrcbData.FeatureBits);
64 /* Get the cache alignment, if it is available */
65 if (Pcr->PrcbData.FeatureBits & (1<<19))
66 {
67 Ke386CacheAlignment = ((Ebx >> 8) & 0xff) * 8;
68 }
69 Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
70 Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
71 }
72 else
73 {
74 Pcr->PrcbData.CpuType = 4;
75 }
76
77 /* Get the maximum extended cpuid level supported. */
78 Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
79 if (MaxCpuidLevel > 0)
80 {
81 /* Get the extended feature flags. */
82 Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
83 }
84
85 /* Get the model name. */
86 if (MaxCpuidLevel >= 0x80000004)
87 {
88 PULONG v = (PULONG)Ke386CpuidModel;
89 Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
90 Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
91 Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
92 }
93
94 /* Get the L1 cache size */
95 if (MaxCpuidLevel >= 0x80000005)
96 {
97 Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
98 Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
99 if ((Ecx & 0xff) > 0)
100 {
101 Ke386CacheAlignment = Ecx & 0xff;
102 }
103 }
104
105 /* Get the L2 cache size */
106 if (MaxCpuidLevel >= 0x80000006)
107 {
108 Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
109 Pcr->L2CacheSize = Ecx >> 16;
110 }
111 }
112
113 VOID INIT_FUNCTION
114 KePrepareForApplicationProcessorInit(ULONG Id)
115 {
116 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id);
117 PFN_TYPE PrcPfn;
118 PKPCR Pcr;
119 PKPCR BootPcr;
120
121 BootPcr = (PKPCR)KPCR_BASE;
122 Pcr = (PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE);
123
124 MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PrcPfn);
125 MmCreateVirtualMappingForKernel((PVOID)Pcr,
126 PAGE_READWRITE,
127 &PrcPfn,
128 1);
129 /*
130 * Create a PCR for this processor
131 */
132 memset(Pcr, 0, PAGE_SIZE);
133 Pcr->ProcessorNumber = Id;
134 Pcr->Tib.Self = &Pcr->Tib;
135 Pcr->Self = Pcr;
136 Pcr->Irql = SYNCH_LEVEL;
137
138 Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz;
139 Pcr->StallScaleFactor = BootPcr->StallScaleFactor;
140
141 /* Mark the end of the exception handler list */
142 Pcr->Tib.ExceptionList = (PVOID)-1;
143
144 KiGdtPrepareForApplicationProcessorInit(Id);
145 }
146
147 VOID
148 KeApplicationProcessorInit(VOID)
149 {
150 ULONG Offset;
151 PKPCR Pcr;
152
153 DPRINT("KeApplicationProcessorInit()\n");
154
155 if (Ke386GlobalPagesEnabled)
156 {
157 /* Enable global pages */
158 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
159 }
160
161
162 Offset = InterlockedIncrementUL(&PcrsAllocated) - 1;
163 Pcr = (PKPCR)((ULONG_PTR)KPCR_BASE + Offset * PAGE_SIZE);
164
165 /*
166 * Initialize the GDT
167 */
168 KiInitializeGdt(Pcr);
169
170 /* Get processor information. */
171 Ki386GetCpuId();
172
173 /* Check FPU/MMX/SSE support. */
174 KiCheckFPU();
175
176 KeInitDpc(Pcr);
177
178 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
179 {
180 extern void KiFastCallEntry(void);
181
182 /* CS Selector of the target segment. */
183 Ke386Wrmsr(0x174, KERNEL_CS, 0);
184 /* Target ESP. */
185 Ke386Wrmsr(0x175, 0, 0);
186 /* Target EIP. */
187 Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
188 }
189
190 /*
191 * It is now safe to process interrupts
192 */
193 KeLowerIrql(DISPATCH_LEVEL);
194
195 /*
196 * Initialize the TSS
197 */
198 Ki386ApplicationProcessorInitializeTSS();
199
200 /*
201 * Initialize a default LDT
202 */
203 Ki386InitializeLdt();
204
205 /* Now we can enable interrupts. */
206 Ke386EnableInterrupts();
207 }
208
209 VOID INIT_FUNCTION
210 KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
211 {
212 PKPCR KPCR;
213 BOOLEAN Pae = FALSE;
214 BOOLEAN NoExecute = FALSE;
215 PCHAR p1, p2;
216 extern USHORT KiBootGdt[];
217 extern KTSS KiBootTss;
218
219 /*
220 * Initialize the initial PCR region. We can't allocate a page
221 * with MmAllocPage() here because MmInit1() has not yet been
222 * called, so we use a predefined page in low memory
223 */
224
225 KPCR = (PKPCR)KPCR_BASE;
226 memset(KPCR, 0, PAGE_SIZE);
227 KPCR->Self = KPCR;
228 KPCR->Irql = SYNCH_LEVEL;
229 KPCR->Tib.Self = &KPCR->Tib;
230 KPCR->GDT = KiBootGdt;
231 KPCR->IDT = (PUSHORT)KiIdt;
232 KPCR->TSS = &KiBootTss;
233 KPCR->ProcessorNumber = 0;
234 KiPcrInitDone = 1;
235 PcrsAllocated++;
236
237 KiInitializeGdt (NULL);
238 Ki386BootInitializeTSS();
239 Ki386InitializeLdt();
240
241 /* Get processor information. */
242 Ki386GetCpuId();
243
244 /* Check FPU/MMX/SSE support. */
245 KiCheckFPU();
246
247 /* Mark the end of the exception handler list */
248 KPCR->Tib.ExceptionList = (PVOID)-1;
249
250 KeInitDpc(KPCR);
251
252 KeInitExceptions ();
253 KeInitInterrupts ();
254
255 if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
256 {
257 ULONG Flags;
258 /* Enable global pages */
259 Ke386GlobalPagesEnabled = TRUE;
260 Ke386SaveFlags(Flags);
261 Ke386DisableInterrupts();
262 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
263 Ke386RestoreFlags(Flags);
264 }
265
266 /* Search for pae and noexecute */
267 p1 = (PCHAR)KeLoaderBlock.CommandLine;
268 while(*p1 && (p2 = strchr(p1, '/')))
269 {
270 p2++;
271 if (!_strnicmp(p2, "PAE", 3))
272 {
273 if (p2[3] == ' ' || p2[3] == 0)
274 {
275 p2 += 3;
276 Pae = TRUE;
277 }
278 }
279 else if (!_strnicmp(p2, "NOEXECUTE", 9))
280 {
281 if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
282 {
283 p2 += 9;
284 NoExecute = TRUE;
285 }
286 }
287 p1 = p2;
288 }
289
290 /*
291 * FIXME:
292 * Make the detection of the noexecute feature more portable.
293 */
294 if(KPCR->PrcbData.CpuType == 0xf &&
295 RtlCompareMemory("AuthenticAMD", KPCR->PrcbData.VendorString, 12) == 12)
296 {
297 if (NoExecute)
298 {
299 ULONG Flags, l, h;
300 Ke386SaveFlags(Flags);
301 Ke386DisableInterrupts();
302
303 Ke386Rdmsr(0xc0000080, l, h);
304 l |= (1 << 11);
305 Ke386Wrmsr(0xc0000080, l, h);
306 Ke386NoExecute = TRUE;
307 Ke386RestoreFlags(Flags);
308 }
309 }
310 else
311 {
312 NoExecute=FALSE;
313 }
314
315
316 /* Enable PAE mode */
317 if ((Pae && (KPCR->PrcbData.FeatureBits & X86_FEATURE_PAE)) || NoExecute)
318 {
319 MiEnablePAE((PVOID*)LastKernelAddress);
320 Ke386PaeEnabled = TRUE;
321 }
322
323 if (KPCR->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
324 {
325 extern void KiFastCallEntry(void);
326
327 /* CS Selector of the target segment. */
328 Ke386Wrmsr(0x174, KERNEL_CS, 0);
329 /* Target ESP. */
330 Ke386Wrmsr(0x175, 0, 0);
331 /* Target EIP. */
332 Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
333 }
334 }
335
336 VOID INIT_FUNCTION
337 KeInit2(VOID)
338 {
339 PKPCR Pcr = KeGetCurrentKPCR();
340
341 KeInitializeBugCheck();
342 KeInitializeDispatcher();
343 KeInitializeTimerImpl();
344
345 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
346 {
347 DPRINT("CPU supports PAE mode\n");
348 if (Ke386Pae)
349 {
350 DPRINT("CPU runs in PAE mode\n");
351 if (Ke386NoExecute)
352 {
353 DPRINT("NoExecute is enabled\n");
354 }
355 }
356 else
357 {
358 DPRINT("CPU doesn't run in PAE mode\n");
359 }
360 }
361 if ((Pcr->PrcbData.FeatureBits & (X86_FEATURE_FXSR | X86_FEATURE_MMX | X86_FEATURE_SSE | X86_FEATURE_SSE2)) ||
362 (Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3))
363 {
364 DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
365 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_FXSR) ? " FXSR" : ""),
366 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX) ? " MMX" : ""),
367 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE) ? " SSE" : ""),
368 ((Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2) ? " SSE2" : ""),
369 ((Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3) ? " SSE3" : ""));
370 }
371 if (Ke386GetCr4() & X86_CR4_OSFXSR)
372 {
373 DPRINT("SSE enabled.\n");
374 }
375 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT)
376 {
377 DPRINT("Unmasked SIMD exceptions enabled.\n");
378 }
379 if (Pcr->PrcbData.VendorString[0])
380 {
381 DPRINT("CPU Vendor: %s\n", Pcr->PrcbData.VendorString);
382 }
383 if (Ke386CpuidModel[0])
384 {
385 DPRINT("CPU Model: %s\n", Ke386CpuidModel);
386 }
387
388 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
389 if (Ke386L1CacheSize)
390 {
391 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
392 }
393 if (Pcr->L2CacheSize)
394 {
395 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr->L2CacheSize);
396 }
397 }
398
399 VOID INIT_FUNCTION
400 Ki386SetProcessorFeatures(VOID)
401 {
402 PKPCR Pcr = KeGetCurrentKPCR();
403 OBJECT_ATTRIBUTES ObjectAttributes;
404 UNICODE_STRING KeyName;
405 UNICODE_STRING ValueName;
406 HANDLE KeyHandle;
407 ULONG ResultLength;
408 KEY_VALUE_PARTIAL_INFORMATION ValueData;
409 NTSTATUS Status;
410 ULONG FastSystemCallDisable = 0;
411
412 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_PRECISION_ERRATA] = FALSE;
413 SharedUserData->ProcessorFeatures[PF_FLOATING_POINT_EMULATED] = FALSE;
414 SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] =
415 (Pcr->PrcbData.FeatureBits & X86_FEATURE_CX8);
416 SharedUserData->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE] =
417 (Pcr->PrcbData.FeatureBits & X86_FEATURE_MMX);
418 SharedUserData->ProcessorFeatures[PF_PPC_MOVEMEM_64BIT_OK] = FALSE;
419 SharedUserData->ProcessorFeatures[PF_ALPHA_BYTE_INSTRUCTIONS] = FALSE;
420 SharedUserData->ProcessorFeatures[PF_XMMI_INSTRUCTIONS_AVAILABLE] =
421 (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE);
422 SharedUserData->ProcessorFeatures[PF_3DNOW_INSTRUCTIONS_AVAILABLE] =
423 (Ke386CpuidExFlags & X86_EXT_FEATURE_3DNOW);
424 SharedUserData->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE] =
425 (Pcr->PrcbData.FeatureBits & X86_FEATURE_TSC);
426 SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] = Ke386PaeEnabled;
427 SharedUserData->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] =
428 (Pcr->PrcbData.FeatureBits & X86_FEATURE_SSE2);
429
430 /* Does the CPU Support Fast System Call? */
431 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL) {
432
433 /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
434
435 /* Make sure it's not disabled in registry */
436 RtlRosInitUnicodeStringFromLiteral(&KeyName,
437 L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
438 RtlRosInitUnicodeStringFromLiteral(&ValueName,
439 L"FastSystemCallDisable");
440 InitializeObjectAttributes(&ObjectAttributes,
441 &KeyName,
442 OBJ_CASE_INSENSITIVE,
443 NULL,
444 NULL);
445 Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
446
447 if (NT_SUCCESS(Status)) {
448
449 /* Read the Value then Close the Key */
450 Status = NtQueryValueKey(KeyHandle,
451 &ValueName,
452 KeyValuePartialInformation,
453 &ValueData,
454 sizeof(ValueData),
455 &ResultLength);
456 RtlMoveMemory(&FastSystemCallDisable, ValueData.Data, sizeof(ULONG));
457
458 NtClose(KeyHandle);
459 }
460
461 } else {
462
463 /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
464 FastSystemCallDisable = 1;
465
466 }
467
468 if (FastSystemCallDisable) {
469
470 /* Use INT2E */
471 SharedUserData->SystemCall[0] = 0x8D;
472 SharedUserData->SystemCall[1] = 0x54;
473 SharedUserData->SystemCall[2] = 0x24;
474 SharedUserData->SystemCall[3] = 0x08;
475 SharedUserData->SystemCall[4] = 0xCD;
476 SharedUserData->SystemCall[5] = 0x2E;
477 SharedUserData->SystemCall[6] = 0xC3;
478
479 } else {
480
481 /* Use SYSENTER */
482 SharedUserData->SystemCall[0] = 0x8B;
483 SharedUserData->SystemCall[1] = 0xD4;
484 SharedUserData->SystemCall[2] = 0x0F;
485 SharedUserData->SystemCall[3] = 0x34;
486 SharedUserData->SystemCall[4] = 0xC3;
487
488 /* Enable SYSENTER/SYSEXIT */
489 KiFastSystemCallDisable = 0;
490 }
491 }