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 ULONG KeI386NpxPresent
= 0;
30 ULONG KeI386XMMIPresent
= 0;
31 ULONG KeI386FxsrPresent
= 0;
32 extern PVOID Ki386InitialStackArray
[MAXIMUM_PROCESSORS
];
33 extern ULONG IdleProcessorMask
;
34 extern KIDTENTRY KiIdt
[256];
35 static VOID INIT_FUNCTION
Ki386GetCpuId(VOID
);
37 #if defined (ALLOC_PRAGMA)
38 #pragma alloc_text(INIT, Ki386GetCpuId)
39 #pragma alloc_text(INIT, KeCreateApplicationProcessorIdleThread)
40 #pragma alloc_text(INIT, KePrepareForApplicationProcessorInit)
41 #pragma alloc_text(INIT, KeInit1)
42 #pragma alloc_text(INIT, KeInit2)
43 #pragma alloc_text(INIT, Ki386SetProcessorFeatures)
46 /* FUNCTIONS *****************************************************************/
48 static VOID INIT_FUNCTION
51 ULONG OrigFlags
, Flags
, FinalFlags
;
53 ULONG Dummy
, Eax
, Ecx
, Edx
;
54 PKIPCR Pcr
= (PKIPCR
)KeGetCurrentKPCR();
56 Ke386CpuidFlags2
= Ke386CpuidExFlags
= 0;
57 Ke386CacheAlignment
= 32;
59 /* Try to toggle the id bit in eflags. */
60 Ke386SaveFlags(OrigFlags
);
61 Flags
= OrigFlags
^ X86_EFLAGS_ID
;
62 Ke386RestoreFlags(Flags
);
63 Ke386SaveFlags(FinalFlags
);
65 Pcr
->PrcbData
.LogicalProcessorsPerPhysicalProcessor
= 1;
66 Pcr
->PrcbData
.InitialApicId
= 0xff;
68 if ((OrigFlags
& X86_EFLAGS_ID
) == (FinalFlags
& X86_EFLAGS_ID
))
70 /* No cpuid supported. */
71 Pcr
->PrcbData
.CpuID
= FALSE
;
72 Pcr
->PrcbData
.CpuType
= 3;
75 Pcr
->PrcbData
.CpuID
= TRUE
;
77 /* Get the vendor name and the maximum cpuid level supported. */
78 Ki386Cpuid(0, &MaxCpuidLevel
, (PULONG
)&Pcr
->PrcbData
.VendorString
[0], (PULONG
)&Pcr
->PrcbData
.VendorString
[8], (PULONG
)&Pcr
->PrcbData
.VendorString
[4]);
79 if (MaxCpuidLevel
> 0)
81 /* Get the feature flags. */
82 Ki386Cpuid(1, &Eax
, &Ke386CpuidExMisc
, &Ke386CpuidFlags2
, &Pcr
->PrcbData
.FeatureBits
);
84 DPRINT ("Model: %x\n", (Eax
& 0xf00) == 0xf00 ? ((Eax
>> 4) & 0xf) | ((Eax
>> 12) & 0xf0) : (Eax
>> 4) & 0xf);
85 DPRINT ("Family: %x\n", (Eax
& 0xf00) == 0xf00 ? ((Eax
>> 8) & 0xf) + ((Eax
>> 20) & 0xff) : (Eax
>> 8) & 0xf);
87 /* Get the cache alignment, if it is available */
88 if (Pcr
->PrcbData
.FeatureBits
& (1<<19))
90 Ke386CacheAlignment
= ((Ke386CpuidExMisc
>> 8) & 0xff) * 8;
92 Pcr
->PrcbData
.CpuType
= (Eax
>> 8) & 0xf;
93 Pcr
->PrcbData
.CpuStep
= (Eax
& 0xf) | ((Eax
<< 4) & 0xf00);
95 Pcr
->PrcbData
.InitialApicId
= (Ke386CpuidExMisc
>> 24) & 0xff;
97 /* detect Hyper-Threading on Pentium 4 CPUs or later */
98 if ((Pcr
->PrcbData
.CpuType
== 0xf || (Eax
& 0x0f00000)) &&
99 !strncmp(Pcr
->PrcbData
.VendorString
, "GenuineIntel", 12) &&
100 Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_HT
)
102 Pcr
->PrcbData
.LogicalProcessorsPerPhysicalProcessor
= (Ke386CpuidExMisc
>> 16) & 0xff;
107 Pcr
->PrcbData
.CpuType
= 4;
110 /* Get the maximum extended cpuid level supported. */
111 Ki386Cpuid(0x80000000, &MaxCpuidLevel
, &Dummy
, &Dummy
, &Dummy
);
112 if (MaxCpuidLevel
> 0)
114 /* Get the extended feature flags. */
115 Ki386Cpuid(0x80000001, &Dummy
, &Dummy
, &Dummy
, &Ke386CpuidExFlags
);
118 /* Get the model name. */
119 if (MaxCpuidLevel
>= 0x80000004)
121 PULONG v
= (PULONG
)Ke386CpuidModel
;
122 Ki386Cpuid(0x80000002, v
, v
+ 1, v
+ 2, v
+ 3);
123 Ki386Cpuid(0x80000003, v
+ 4, v
+ 5, v
+ 6, v
+ 7);
124 Ki386Cpuid(0x80000004, v
+ 8, v
+ 9, v
+ 10, v
+ 11);
127 /* Get the L1 cache size */
128 if (MaxCpuidLevel
>= 0x80000005)
130 Ki386Cpuid(0x80000005, &Dummy
, &Dummy
, &Ecx
, &Edx
);
131 Ke386L1CacheSize
= (Ecx
>> 24)+(Edx
>> 24);
132 if ((Ecx
& 0xff) > 0)
134 Ke386CacheAlignment
= Ecx
& 0xff;
138 /* Get the L2 cache size */
139 if (MaxCpuidLevel
>= 0x80000006)
141 Ki386Cpuid(0x80000006, &Dummy
, &Dummy
, &Ecx
, &Dummy
);
142 Pcr
->SecondLevelCacheSize
= Ecx
>> 16;
147 KeApplicationProcessorInitDispatcher(VOID
)
150 oldIrql
= KeAcquireDispatcherDatabaseLock();
151 IdleProcessorMask
|= (1 << KeGetCurrentProcessorNumber());
152 KeReleaseDispatcherDatabaseLock(oldIrql
);
157 KeCreateApplicationProcessorIdleThread(ULONG Id
)
160 PKPRCB Prcb
= ((PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
))->Prcb
;
162 PsInitializeIdleOrFirstThread(PsIdleProcess
,
167 IdleThread
->Tcb
.State
= Running
;
168 IdleThread
->Tcb
.FreezeCount
= 0;
169 IdleThread
->Tcb
.Affinity
= 1 << Id
;
170 IdleThread
->Tcb
.UserAffinity
= 1 << Id
;
171 IdleThread
->Tcb
.Priority
= LOW_PRIORITY
;
172 IdleThread
->Tcb
.BasePriority
= LOW_PRIORITY
;
173 Prcb
->IdleThread
= &IdleThread
->Tcb
;
174 Prcb
->CurrentThread
= &IdleThread
->Tcb
;
176 Ki386InitialStackArray
[Id
] = (PVOID
)IdleThread
->Tcb
.StackLimit
;
178 DPRINT("IdleThread for Processor %d has PID %d\n",
179 Id
, IdleThread
->Cid
.UniqueThread
);
185 KePrepareForApplicationProcessorInit(ULONG Id
)
191 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id
);
193 BootPcr
= (PKIPCR
)KPCR_BASE
;
194 Pcr
= (PKIPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
);
196 MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &PrcPfn
);
197 MmCreateVirtualMappingForKernel((PVOID
)Pcr
,
202 * Create a PCR for this processor
204 memset(Pcr
, 0, PAGE_SIZE
);
206 Pcr
->SetMember
= 1 << Id
;
207 Pcr
->NtTib
.Self
= &Pcr
->NtTib
;
208 Pcr
->Self
= (PKPCR
)Pcr
;
209 Pcr
->Prcb
= &Pcr
->PrcbData
;
210 Pcr
->Irql
= SYNCH_LEVEL
;
212 Pcr
->PrcbData
.SetMember
= 1 << Id
;
213 Pcr
->PrcbData
.MHz
= BootPcr
->PrcbData
.MHz
;
214 Pcr
->StallScaleFactor
= BootPcr
->StallScaleFactor
;
216 /* Mark the end of the exception handler list */
217 Pcr
->NtTib
.ExceptionList
= (PVOID
)-1;
219 KiGdtPrepareForApplicationProcessorInit(Id
);
221 KeActiveProcessors
|= 1 << Id
;
226 KeApplicationProcessorInit(VOID
)
231 DPRINT("KeApplicationProcessorInit()\n");
233 if (Ke386GlobalPagesEnabled
)
235 /* Enable global pages */
236 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
240 Offset
= InterlockedIncrementUL(&PcrsAllocated
) - 1;
241 Pcr
= (PKIPCR
)((ULONG_PTR
)KPCR_BASE
+ Offset
* PAGE_SIZE
);
246 KiInitializeGdt((PKPCR
)Pcr
);
248 /* Get processor information. */
251 /* Check FPU/MMX/SSE support. */
254 KeInitDpc(Pcr
->Prcb
);
256 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
)
258 extern void KiFastCallEntry(void);
260 /* CS Selector of the target segment. */
261 Ke386Wrmsr(0x174, KGDT_R0_CODE
, 0);
263 Ke386Wrmsr(0x175, 0, 0);
265 Ke386Wrmsr(0x176, (ULONG_PTR
)KiFastCallEntry
, 0);
269 * It is now safe to process interrupts
271 KeLowerIrql(DISPATCH_LEVEL
);
276 Ki386ApplicationProcessorInitializeTSS();
279 * Initialize a default LDT
281 Ki386InitializeLdt();
283 /* Now we can enable interrupts. */
284 Ke386EnableInterrupts();
290 KeInit1(PCHAR CommandLine
, PULONG LastKernelAddress
)
294 BOOLEAN NoExecute
= FALSE
;
296 extern USHORT KiBootGdt
[];
297 extern KTSS KiBootTss
;
300 * Initialize the initial PCR region. We can't allocate a page
301 * with MmAllocPage() here because MmInit1() has not yet been
302 * called, so we use a predefined page in low memory
305 KPCR
= (PKIPCR
)KPCR_BASE
;
306 memset(KPCR
, 0, PAGE_SIZE
);
307 KPCR
->Self
= (PKPCR
)KPCR
;
308 KPCR
->Prcb
= &KPCR
->PrcbData
;
309 KPCR
->Irql
= SYNCH_LEVEL
;
310 KPCR
->NtTib
.Self
= &KPCR
->NtTib
;
311 KPCR
->GDT
= KiBootGdt
;
313 KPCR
->TSS
= &KiBootTss
;
315 KPCR
->SetMember
= 1 << 0;
316 KeActiveProcessors
= 1 << 0;
317 KPCR
->PrcbData
.SetMember
= 1 << 0;
321 KiInitializeGdt (NULL
);
322 Ki386BootInitializeTSS();
323 Ki386InitializeLdt();
325 /* Get processor information. */
328 /* Check FPU/MMX/SSE support. */
331 /* Mark the end of the exception handler list */
332 KPCR
->NtTib
.ExceptionList
= (PVOID
)-1;
334 KeInitDpc(KPCR
->Prcb
);
339 KeActiveProcessors
|= 1 << 0;
342 if (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PGE
)
345 /* Enable global pages */
346 Ke386GlobalPagesEnabled
= TRUE
;
347 Ke386SaveFlags(Flags
);
348 Ke386DisableInterrupts();
349 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
350 Ke386RestoreFlags(Flags
);
353 /* Search for pae and noexecute */
354 p1
= (PCHAR
)KeLoaderBlock
.CommandLine
;
355 while(*p1
&& (p2
= strchr(p1
, '/')))
358 if (!_strnicmp(p2
, "PAE", 3))
360 if (p2
[3] == ' ' || p2
[3] == 0)
366 else if (!_strnicmp(p2
, "NOEXECUTE", 9))
368 if (p2
[9] == ' ' || p2
[9] == '=' || p2
[9] == 0)
379 * Make the detection of the noexecute feature more portable.
381 if(KPCR
->PrcbData
.CpuType
== 0xf &&
382 RtlCompareMemory("AuthenticAMD", KPCR
->PrcbData
.VendorString
, 12) == 12)
387 Ke386SaveFlags(Flags
);
388 Ke386DisableInterrupts();
390 Ke386Rdmsr(0xc0000080, l
, h
);
392 Ke386Wrmsr(0xc0000080, l
, h
);
393 Ke386NoExecute
= TRUE
;
394 Ke386RestoreFlags(Flags
);
403 Ke386Pae
= Ke386GetCr4() & X86_CR4_PAE
? TRUE
: FALSE
;
405 /* Enable PAE mode */
406 if ((Pae
&& (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)) || NoExecute
)
408 MiEnablePAE((PVOID
*)LastKernelAddress
);
409 Ke386PaeEnabled
= TRUE
;
412 if (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
)
414 extern void KiFastCallEntry(void);
416 /* CS Selector of the target segment. */
417 Ke386Wrmsr(0x174, KGDT_R0_CODE
, 0);
419 Ke386Wrmsr(0x175, 0, 0);
421 Ke386Wrmsr(0x176, (ULONG_PTR
)KiFastCallEntry
, 0);
424 /* Does the CPU Support 'prefetchnta' (SSE) */
425 if(KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_SSE
)
429 Protect
= MmGetPageProtect(NULL
, (PVOID
)RtlPrefetchMemoryNonTemporal
);
430 MmSetPageProtect(NULL
, (PVOID
)RtlPrefetchMemoryNonTemporal
, Protect
| PAGE_IS_WRITABLE
);
431 /* Replace the ret by a nop */
432 *(PCHAR
)RtlPrefetchMemoryNonTemporal
= 0x90;
433 MmSetPageProtect(NULL
, (PVOID
)RtlPrefetchMemoryNonTemporal
, Protect
);
442 PKIPCR Pcr
= (PKIPCR
)KeGetCurrentKPCR();
444 KiInitializeBugCheck();
445 KeInitializeDispatcher();
446 KiInitializeSystemClock();
448 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)
450 DPRINT("CPU supports PAE mode\n");
453 DPRINT("CPU runs in PAE mode\n");
456 DPRINT("NoExecute is enabled\n");
461 DPRINT("CPU doesn't run in PAE mode\n");
464 if ((Pcr
->PrcbData
.FeatureBits
& (X86_FEATURE_FXSR
| X86_FEATURE_MMX
| X86_FEATURE_SSE
| X86_FEATURE_SSE2
)) ||
465 (Ke386CpuidFlags2
& X86_EXT_FEATURE_SSE3
))
467 DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
468 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_FXSR
) ? " FXSR" : ""),
469 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_MMX
) ? " MMX" : ""),
470 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE
) ? " SSE" : ""),
471 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE2
) ? " SSE2" : ""),
472 ((Ke386CpuidFlags2
& X86_EXT_FEATURE_SSE3
) ? " SSE3" : ""));
474 if (Ke386GetCr4() & X86_CR4_OSFXSR
)
476 DPRINT("SSE enabled.\n");
478 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT
)
480 DPRINT("Unmasked SIMD exceptions enabled.\n");
482 if (Pcr
->PrcbData
.VendorString
[0])
484 DPRINT("CPU Vendor: %s\n", Pcr
->PrcbData
.VendorString
);
486 if (Ke386CpuidModel
[0])
488 DPRINT("CPU Model: %s\n", Ke386CpuidModel
);
491 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment
);
492 if (Ke386L1CacheSize
)
495 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize
);
497 if (Pcr
->SecondLevelCacheSize
)
499 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr
->SecondLevelCacheSize
);
504 Ki386SetProcessorFeatures(VOID
)
506 PKIPCR Pcr
= (PKIPCR
)KeGetCurrentKPCR();
507 OBJECT_ATTRIBUTES ObjectAttributes
;
508 UNICODE_STRING KeyName
=
509 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Kernel");
510 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"FastSystemCallDisable");
515 KEY_VALUE_PARTIAL_INFORMATION Info
;
516 UCHAR Buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,
517 Data
[0]) + sizeof(ULONG
)];
520 ULONG FastSystemCallDisable
= 0;
522 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = FALSE
;
523 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] = FALSE
;
524 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
525 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_CX8
) ? TRUE
: FALSE
;
526 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
527 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_MMX
) ? TRUE
: FALSE
;
528 SharedUserData
->ProcessorFeatures
[PF_PPC_MOVEMEM_64BIT_OK
] = FALSE
;
529 SharedUserData
->ProcessorFeatures
[PF_ALPHA_BYTE_INSTRUCTIONS
] = FALSE
;
530 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
531 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE
) ? TRUE
: FALSE
;
532 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
533 (Ke386CpuidExFlags
& X86_EXT_FEATURE_3DNOW
) ? TRUE
: FALSE
;
534 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
535 (Pcr
->PrcbData
.FeatureBits
& KF_RDTSC
) ? TRUE
: FALSE
;
536 SharedUserData
->ProcessorFeatures
[PF_PAE_ENABLED
] = Ke386Pae
;
537 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
538 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE2
) ? TRUE
: FALSE
;
540 /* Does the CPU Support Fast System Call? */
541 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SYSCALL
) {
543 /* FIXME: Check for Family == 6, Model < 3 and Stepping < 3 and disable */
545 /* Make sure it's not disabled in registry */
546 InitializeObjectAttributes(&ObjectAttributes
,
548 OBJ_CASE_INSENSITIVE
,
551 Status
= ZwOpenKey(&KeyHandle
,
555 if (NT_SUCCESS(Status
)) {
557 /* Read the Value then Close the Key */
558 Status
= ZwQueryValueKey(KeyHandle
,
560 KeyValuePartialInformation
,
564 if (NT_SUCCESS(Status
))
566 if (ResultLength
== sizeof(ValueData
) &&
567 ValueData
.Info
.Type
== REG_DWORD
)
569 FastSystemCallDisable
= *(PULONG
)ValueData
.Info
.Data
!= 0;
578 /* Disable SYSENTER/SYSEXIT, because the CPU doesn't support it */
579 FastSystemCallDisable
= 1;
583 if (FastSystemCallDisable
) {
585 const unsigned char Entry
[7] = {0x8D, 0x54, 0x24, 0x08, /* lea 0x8(%esp),%edx */
586 0xCD, 0x2E, /* int 0x2e */
588 memcpy(&SharedUserData
->SystemCall
, Entry
, sizeof(Entry
));
591 const unsigned char Entry
[5] = {0x8B, 0xD4, /* movl %esp,%edx */
592 0x0F, 0x34, /* sysenter */
594 memcpy(&SharedUserData
->SystemCall
, Entry
, sizeof(Entry
));
595 /* Enable SYSENTER/SYSEXIT */
596 KiFastSystemCallDisable
= 0;