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