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