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
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
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
;
32 /* FUNCTIONS *****************************************************************/
34 VOID INIT_FUNCTION STATIC
37 ULONG OrigFlags
, Flags
, FinalFlags
;
39 ULONG Dummy
, Eax
, Ecx
, Edx
;
40 PKPCR Pcr
= KeGetCurrentKPCR();
42 Ke386CpuidFlags2
= Ke386CpuidExFlags
= 0;
43 Ke386CacheAlignment
= 32;
45 /* Try to toggle the id bit in eflags. */
46 Ke386SaveFlags(OrigFlags
);
47 Flags
= OrigFlags
^ X86_EFLAGS_ID
;
48 Ke386RestoreFlags(Flags
);
49 Ke386SaveFlags(FinalFlags
);
51 Pcr
->PrcbData
.LogicalProcessorsPerPhysicalProcessor
= 1;
52 Pcr
->PrcbData
.InitialApicId
= 0xff;
54 if ((OrigFlags
& X86_EFLAGS_ID
) == (FinalFlags
& X86_EFLAGS_ID
))
56 /* No cpuid supported. */
57 Pcr
->PrcbData
.CpuID
= FALSE
;
58 Pcr
->PrcbData
.CpuType
= 3;
61 Pcr
->PrcbData
.CpuID
= TRUE
;
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)
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))
72 Ke386CacheAlignment
= ((Ke386CpuidExMisc
>> 8) & 0xff) * 8;
74 Pcr
->PrcbData
.CpuType
= (Eax
>> 8) & 0xf;
75 Pcr
->PrcbData
.CpuStep
= (Eax
& 0xf) | ((Eax
<< 4) & 0xf00);
77 Pcr
->PrcbData
.InitialApicId
= (Ke386CpuidExMisc
>> 24) & 0xff;
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
)
84 Pcr
->PrcbData
.LogicalProcessorsPerPhysicalProcessor
= (Ke386CpuidExMisc
>> 16) & 0xff;
89 Pcr
->PrcbData
.CpuType
= 4;
92 /* Get the maximum extended cpuid level supported. */
93 Ki386Cpuid(0x80000000, &MaxCpuidLevel
, &Dummy
, &Dummy
, &Dummy
);
94 if (MaxCpuidLevel
> 0)
96 /* Get the extended feature flags. */
97 Ki386Cpuid(0x80000001, &Dummy
, &Dummy
, &Dummy
, &Ke386CpuidExFlags
);
100 /* Get the model name. */
101 if (MaxCpuidLevel
>= 0x80000004)
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);
109 /* Get the L1 cache size */
110 if (MaxCpuidLevel
>= 0x80000005)
112 Ki386Cpuid(0x80000005, &Dummy
, &Dummy
, &Ecx
, &Edx
);
113 Ke386L1CacheSize
= (Ecx
>> 24)+(Edx
>> 24);
114 if ((Ecx
& 0xff) > 0)
116 Ke386CacheAlignment
= Ecx
& 0xff;
120 /* Get the L2 cache size */
121 if (MaxCpuidLevel
>= 0x80000006)
123 Ki386Cpuid(0x80000006, &Dummy
, &Dummy
, &Ecx
, &Dummy
);
124 Pcr
->L2CacheSize
= Ecx
>> 16;
129 KeApplicationProcessorInitDispatcher(VOID
)
132 oldIrql
= KeAcquireDispatcherDatabaseLock();
133 IdleProcessorMask
|= (1 << KeGetCurrentProcessorNumber());
134 KeReleaseDispatcherDatabaseLock(oldIrql
);
139 KeCreateApplicationProcessorIdleThread(ULONG Id
)
142 PKPRCB Prcb
= ((PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
))->Prcb
;
144 PsInitializeThread(PsIdleProcess
,
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
;
158 Ki386InitialStackArray
[Id
] = (PVOID
)IdleThread
->Tcb
.StackLimit
;
160 DPRINT("IdleThread for Processor %d has PID %d\n",
161 Id
, IdleThread
->Cid
.UniqueThread
);
165 KePrepareForApplicationProcessorInit(ULONG Id
)
167 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id
);
172 BootPcr
= (PKPCR
)KPCR_BASE
;
173 Pcr
= (PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
);
175 MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &PrcPfn
);
176 MmCreateVirtualMappingForKernel((PVOID
)Pcr
,
181 * Create a PCR for this processor
183 memset(Pcr
, 0, PAGE_SIZE
);
184 Pcr
->ProcessorNumber
= Id
;
185 Pcr
->Tib
.Self
= &Pcr
->Tib
;
187 Pcr
->Prcb
= &Pcr
->PrcbData
;
188 Pcr
->Irql
= SYNCH_LEVEL
;
190 Pcr
->PrcbData
.MHz
= BootPcr
->PrcbData
.MHz
;
191 Pcr
->StallScaleFactor
= BootPcr
->StallScaleFactor
;
193 /* Mark the end of the exception handler list */
194 Pcr
->Tib
.ExceptionList
= (PVOID
)-1;
196 KiGdtPrepareForApplicationProcessorInit(Id
);
200 KeApplicationProcessorInit(VOID
)
205 DPRINT("KeApplicationProcessorInit()\n");
207 if (Ke386GlobalPagesEnabled
)
209 /* Enable global pages */
210 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
214 Offset
= InterlockedIncrementUL(&PcrsAllocated
) - 1;
215 Pcr
= (PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Offset
* PAGE_SIZE
);
220 KiInitializeGdt(Pcr
);
222 /* Get processor information. */
225 /* Check FPU/MMX/SSE support. */
228 KeInitDpc(Pcr
->Prcb
);
230 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
)
232 extern void KiFastCallEntry(void);
234 /* CS Selector of the target segment. */
235 Ke386Wrmsr(0x174, KERNEL_CS
, 0);
237 Ke386Wrmsr(0x175, 0, 0);
239 Ke386Wrmsr(0x176, (ULONG_PTR
)KiFastCallEntry
, 0);
243 * It is now safe to process interrupts
245 KeLowerIrql(DISPATCH_LEVEL
);
250 Ki386ApplicationProcessorInitializeTSS();
253 * Initialize a default LDT
255 Ki386InitializeLdt();
257 /* Now we can enable interrupts. */
258 Ke386EnableInterrupts();
262 KeInit1(PCHAR CommandLine
, PULONG LastKernelAddress
)
266 BOOLEAN NoExecute
= FALSE
;
268 extern USHORT KiBootGdt
[];
269 extern KTSS KiBootTss
;
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
277 KPCR
= (PKPCR
)KPCR_BASE
;
278 memset(KPCR
, 0, PAGE_SIZE
);
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;
290 KiInitializeGdt (NULL
);
291 Ki386BootInitializeTSS();
292 Ki386InitializeLdt();
294 /* Get processor information. */
297 /* Check FPU/MMX/SSE support. */
300 /* Mark the end of the exception handler list */
301 KPCR
->Tib
.ExceptionList
= (PVOID
)-1;
303 KeInitDpc(KPCR
->Prcb
);
308 if (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PGE
)
311 /* Enable global pages */
312 Ke386GlobalPagesEnabled
= TRUE
;
313 Ke386SaveFlags(Flags
);
314 Ke386DisableInterrupts();
315 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
316 Ke386RestoreFlags(Flags
);
319 /* Search for pae and noexecute */
320 p1
= (PCHAR
)KeLoaderBlock
.CommandLine
;
321 while(*p1
&& (p2
= strchr(p1
, '/')))
324 if (!_strnicmp(p2
, "PAE", 3))
326 if (p2
[3] == ' ' || p2
[3] == 0)
332 else if (!_strnicmp(p2
, "NOEXECUTE", 9))
334 if (p2
[9] == ' ' || p2
[9] == '=' || p2
[9] == 0)
345 * Make the detection of the noexecute feature more portable.
347 if(KPCR
->PrcbData
.CpuType
== 0xf &&
348 RtlCompareMemory("AuthenticAMD", KPCR
->PrcbData
.VendorString
, 12) == 12)
353 Ke386SaveFlags(Flags
);
354 Ke386DisableInterrupts();
356 Ke386Rdmsr(0xc0000080, l
, h
);
358 Ke386Wrmsr(0xc0000080, l
, h
);
359 Ke386NoExecute
= TRUE
;
360 Ke386RestoreFlags(Flags
);
369 Ke386Pae
= Ke386GetCr4() & X86_CR4_PAE
? TRUE
: FALSE
;
371 /* Enable PAE mode */
372 if ((Pae
&& (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)) || NoExecute
)
374 MiEnablePAE((PVOID
*)LastKernelAddress
);
375 Ke386PaeEnabled
= TRUE
;
378 if (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
)
380 extern void KiFastCallEntry(void);
382 /* CS Selector of the target segment. */
383 Ke386Wrmsr(0x174, KERNEL_CS
, 0);
385 Ke386Wrmsr(0x175, 0, 0);
387 Ke386Wrmsr(0x176, (ULONG_PTR
)KiFastCallEntry
, 0);
394 PKPCR Pcr
= KeGetCurrentKPCR();
396 KiInitializeBugCheck();
397 KeInitializeDispatcher();
398 KiInitializeSystemClock();
400 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)
402 DPRINT("CPU supports PAE mode\n");
405 DPRINT("CPU runs in PAE mode\n");
408 DPRINT("NoExecute is enabled\n");
413 DPRINT("CPU doesn't run in PAE mode\n");
416 if ((Pcr
->PrcbData
.FeatureBits
& (X86_FEATURE_FXSR
| X86_FEATURE_MMX
| X86_FEATURE_SSE
| X86_FEATURE_SSE2
)) ||
417 (Ke386CpuidFlags2
& X86_EXT_FEATURE_SSE3
))
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" : ""));
426 if (Ke386GetCr4() & X86_CR4_OSFXSR
)
428 DPRINT("SSE enabled.\n");
430 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT
)
432 DPRINT("Unmasked SIMD exceptions enabled.\n");
434 if (Pcr
->PrcbData
.VendorString
[0])
436 DPRINT("CPU Vendor: %s\n", Pcr
->PrcbData
.VendorString
);
438 if (Ke386CpuidModel
[0])
440 DPRINT("CPU Model: %s\n", Ke386CpuidModel
);
443 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment
);
444 if (Ke386L1CacheSize
)
446 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize
);
448 if (Pcr
->L2CacheSize
)
450 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr
->L2CacheSize
);
455 Ki386SetProcessorFeatures(VOID
)
457 PKPCR Pcr
= KeGetCurrentKPCR();
458 OBJECT_ATTRIBUTES ObjectAttributes
;
459 UNICODE_STRING KeyName
;
460 UNICODE_STRING ValueName
;
463 KEY_VALUE_PARTIAL_INFORMATION ValueData
;
465 ULONG FastSystemCallDisable
= 0;
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
);
485 /* Does the CPU Support Fast System Call? */
486 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
) {
488 /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
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
,
497 OBJ_CASE_INSENSITIVE
,
500 Status
= NtOpenKey(&KeyHandle
, KEY_ALL_ACCESS
, &ObjectAttributes
);
502 if (NT_SUCCESS(Status
)) {
504 /* Read the Value then Close the Key */
505 Status
= NtQueryValueKey(KeyHandle
,
507 KeyValuePartialInformation
,
511 RtlMoveMemory(&FastSystemCallDisable
, ValueData
.Data
, sizeof(ULONG
));
518 /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
519 FastSystemCallDisable
= 1;
523 if (FastSystemCallDisable
) {
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;
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;
543 /* Enable SYSENTER/SYSEXIT */
544 KiFastSystemCallDisable
= 0;