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