3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/kernel.c
22 * PURPOSE: Initializes the kernel
23 * PROGRAMMER: David Welch (welch@mcmail.com)
28 /* INCLUDES *****************************************************************/
32 #include <internal/debug.h>
34 /* GLOBALS *******************************************************************/
36 ULONG KiPcrInitDone
= 0;
37 static ULONG PcrsAllocated
= 0;
38 static ULONG Ke386CpuidFlags2
, Ke386CpuidExFlags
;
39 ULONG Ke386CacheAlignment
;
40 CHAR Ke386CpuidModel
[49] = {0,};
41 ULONG Ke386L1CacheSize
;
42 BOOLEAN Ke386NoExecute
= FALSE
;
43 BOOLEAN Ke386Pae
= FALSE
;
44 BOOLEAN Ke386PaeEnabled
= FALSE
;
45 BOOLEAN Ke386GlobalPagesEnabled
= FALSE
;
47 /* FUNCTIONS *****************************************************************/
49 VOID INIT_FUNCTION STATIC
52 ULONG OrigFlags
, Flags
, FinalFlags
;
54 ULONG Dummy
, Eax
, Ebx
, Ecx
, Edx
;
55 PKPCR Pcr
= KeGetCurrentKPCR();
57 Ke386CpuidFlags2
= Ke386CpuidExFlags
= 0;
58 Ke386CacheAlignment
= 32;
60 /* Try to toggle the id bit in eflags. */
61 Ke386SaveFlags(OrigFlags
);
62 Flags
= OrigFlags
^ X86_EFLAGS_ID
;
63 Ke386RestoreFlags(Flags
);
64 Ke386SaveFlags(FinalFlags
);
65 if ((OrigFlags
& X86_EFLAGS_ID
) == (FinalFlags
& X86_EFLAGS_ID
))
67 /* No cpuid supported. */
68 Pcr
->PrcbData
.CpuID
= FALSE
;
69 Pcr
->PrcbData
.CpuType
= 3;
72 Pcr
->PrcbData
.CpuID
= TRUE
;
74 /* Get the vendor name and the maximum cpuid level supported. */
75 Ki386Cpuid(0, &MaxCpuidLevel
, (PULONG
)&Pcr
->PrcbData
.VendorString
[0], (PULONG
)&Pcr
->PrcbData
.VendorString
[8], (PULONG
)&Pcr
->PrcbData
.VendorString
[4]);
76 if (MaxCpuidLevel
> 0)
78 /* Get the feature flags. */
79 Ki386Cpuid(1, &Eax
, &Ebx
, &Ke386CpuidFlags2
, &Pcr
->PrcbData
.FeatureBits
);
80 /* Get the cache alignment, if it is available */
81 if (Pcr
->PrcbData
.FeatureBits
& (1<<19))
83 Ke386CacheAlignment
= ((Ebx
>> 8) & 0xff) * 8;
85 Pcr
->PrcbData
.CpuType
= (Eax
>> 8) & 0xf;
86 Pcr
->PrcbData
.CpuStep
= (Eax
& 0xf) | ((Eax
<< 4) & 0xf00);
90 Pcr
->PrcbData
.CpuType
= 4;
93 /* Get the maximum extended cpuid level supported. */
94 Ki386Cpuid(0x80000000, &MaxCpuidLevel
, &Dummy
, &Dummy
, &Dummy
);
95 if (MaxCpuidLevel
> 0)
97 /* Get the extended feature flags. */
98 Ki386Cpuid(0x80000001, &Dummy
, &Dummy
, &Dummy
, &Ke386CpuidExFlags
);
101 /* Get the model name. */
102 if (MaxCpuidLevel
>= 0x80000004)
104 PULONG v
= (PULONG
)Ke386CpuidModel
;
105 Ki386Cpuid(0x80000002, v
, v
+ 1, v
+ 2, v
+ 3);
106 Ki386Cpuid(0x80000003, v
+ 4, v
+ 5, v
+ 6, v
+ 7);
107 Ki386Cpuid(0x80000004, v
+ 8, v
+ 9, v
+ 10, v
+ 11);
110 /* Get the L1 cache size */
111 if (MaxCpuidLevel
>= 0x80000005)
113 Ki386Cpuid(0x80000005, &Dummy
, &Dummy
, &Ecx
, &Edx
);
114 Ke386L1CacheSize
= (Ecx
>> 24)+(Edx
>> 24);
115 if ((Ecx
& 0xff) > 0)
117 Ke386CacheAlignment
= Ecx
& 0xff;
121 /* Get the L2 cache size */
122 if (MaxCpuidLevel
>= 0x80000006)
124 Ki386Cpuid(0x80000006, &Dummy
, &Dummy
, &Ecx
, &Dummy
);
125 Pcr
->L2CacheSize
= Ecx
>> 16;
130 KePrepareForApplicationProcessorInit(ULONG Id
)
132 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id
);
137 BootPcr
= (PKPCR
)KPCR_BASE
;
138 Pcr
= (PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
);
140 MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &PrcPfn
);
141 MmCreateVirtualMappingForKernel((PVOID
)Pcr
,
146 * Create a PCR for this processor
148 memset(Pcr
, 0, PAGE_SIZE
);
149 Pcr
->ProcessorNumber
= Id
;
150 Pcr
->Tib
.Self
= &Pcr
->Tib
;
152 Pcr
->Irql
= SYNCH_LEVEL
;
154 Pcr
->PrcbData
.MHz
= BootPcr
->PrcbData
.MHz
;
155 Pcr
->StallScaleFactor
= BootPcr
->StallScaleFactor
;
157 /* Mark the end of the exception handler list */
158 Pcr
->Tib
.ExceptionList
= (PVOID
)-1;
160 KiGdtPrepareForApplicationProcessorInit(Id
);
164 KeApplicationProcessorInit(VOID
)
169 DPRINT("KeApplicationProcessorInit()\n");
171 if (Ke386GlobalPagesEnabled
)
173 /* Enable global pages */
174 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
178 Offset
= InterlockedIncrementUL(&PcrsAllocated
) - 1;
179 Pcr
= (PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Offset
* PAGE_SIZE
);
184 KiInitializeGdt(Pcr
);
186 /* Get processor information. */
189 /* Check FPU/MMX/SSE support. */
195 * It is now safe to process interrupts
197 KeLowerIrql(DISPATCH_LEVEL
);
202 Ki386ApplicationProcessorInitializeTSS();
205 * Initialize a default LDT
207 Ki386InitializeLdt();
209 /* Now we can enable interrupts. */
210 Ke386EnableInterrupts();
214 KeInit1(PCHAR CommandLine
, PULONG LastKernelAddress
)
218 BOOLEAN NoExecute
= FALSE
;
220 extern USHORT KiBootGdt
[];
221 extern KTSS KiBootTss
;
224 * Initialize the initial PCR region. We can't allocate a page
225 * with MmAllocPage() here because MmInit1() has not yet been
226 * called, so we use a predefined page in low memory
229 KPCR
= (PKPCR
)KPCR_BASE
;
230 memset(KPCR
, 0, PAGE_SIZE
);
232 KPCR
->Irql
= SYNCH_LEVEL
;
233 KPCR
->Tib
.Self
= &KPCR
->Tib
;
234 KPCR
->GDT
= KiBootGdt
;
235 KPCR
->IDT
= (PUSHORT
)KiIdt
;
236 KPCR
->TSS
= &KiBootTss
;
237 KPCR
->ProcessorNumber
= 0;
241 KiInitializeGdt (NULL
);
242 Ki386BootInitializeTSS();
243 Ki386InitializeLdt();
245 /* Get processor information. */
248 /* Check FPU/MMX/SSE support. */
251 /* Mark the end of the exception handler list */
252 KPCR
->Tib
.ExceptionList
= (PVOID
)-1;
259 if (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PGE
)
262 /* Enable global pages */
263 Ke386GlobalPagesEnabled
= TRUE
;
264 Ke386SaveFlags(Flags
);
265 Ke386DisableInterrupts();
266 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
267 Ke386RestoreFlags(Flags
);
270 /* Search for pae and noexecute */
271 p1
= (PCHAR
)KeLoaderBlock
.CommandLine
;
272 while(*p1
&& (p2
= strchr(p1
, '/')))
275 if (!_strnicmp(p2
, "PAE", 3))
277 if (p2
[3] == ' ' || p2
[3] == 0)
283 else if (!_strnicmp(p2
, "NOEXECUTE", 9))
285 if (p2
[9] == ' ' || p2
[9] == '=' || p2
[9] == 0)
296 * Make the detection of the noexecute feature more portable.
298 if(KPCR
->PrcbData
.CpuType
== 0xf &&
299 RtlCompareMemory("AuthenticAMD", KPCR
->PrcbData
.VendorString
, 12) == 12)
304 Ke386SaveFlags(Flags
);
305 Ke386DisableInterrupts();
307 Ke386Rdmsr(0xc0000080, l
, h
);
309 Ke386Wrmsr(0xc0000080, l
, h
);
310 Ke386NoExecute
= TRUE
;
311 Ke386RestoreFlags(Flags
);
320 /* Enable PAE mode */
321 if ((Pae
&& (KPCR
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)) || NoExecute
)
323 MiEnablePAE((PVOID
*)LastKernelAddress
);
324 Ke386PaeEnabled
= TRUE
;
331 PKPCR Pcr
= KeGetCurrentKPCR();
333 KeInitializeBugCheck();
334 KeInitializeDispatcher();
335 KeInitializeTimerImpl();
337 if (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_PAE
)
339 DPRINT("CPU supports PAE mode\n");
342 DPRINT("CPU runs in PAE mode\n");
345 DPRINT("NoExecute is enabled\n");
350 DPRINT("CPU doesn't run in PAE mode\n");
353 if ((Pcr
->PrcbData
.FeatureBits
& (X86_FEATURE_FXSR
| X86_FEATURE_MMX
| X86_FEATURE_SSE
| X86_FEATURE_SSE2
)) ||
354 (Ke386CpuidFlags2
& X86_EXT_FEATURE_SSE3
))
356 DPRINT("CPU supports" "%s%s%s%s%s" ".\n",
357 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_FXSR
) ? " FXSR" : ""),
358 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_MMX
) ? " MMX" : ""),
359 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE
) ? " SSE" : ""),
360 ((Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE2
) ? " SSE2" : ""),
361 ((Ke386CpuidFlags2
& X86_EXT_FEATURE_SSE3
) ? " SSE3" : ""));
363 if (Ke386GetCr4() & X86_CR4_OSFXSR
)
365 DPRINT("SSE enabled.\n");
367 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT
)
369 DPRINT("Unmasked SIMD exceptions enabled.\n");
371 if (Pcr
->PrcbData
.VendorString
[0])
373 DPRINT("CPU Vendor: %s\n", Pcr
->PrcbData
.VendorString
);
375 if (Ke386CpuidModel
[0])
377 DPRINT("CPU Model: %s\n", Ke386CpuidModel
);
380 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment
);
381 if (Ke386L1CacheSize
)
383 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize
);
385 if (Pcr
->L2CacheSize
)
387 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr
->L2CacheSize
);
392 Ki386SetProcessorFeatures(VOID
)
394 PKPCR Pcr
= KeGetCurrentKPCR();
396 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_PRECISION_ERRATA
] = FALSE
;
397 SharedUserData
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] = FALSE
;
398 SharedUserData
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] =
399 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_CX8
);
400 SharedUserData
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] =
401 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_MMX
);
402 SharedUserData
->ProcessorFeatures
[PF_PPC_MOVEMEM_64BIT_OK
] = FALSE
;
403 SharedUserData
->ProcessorFeatures
[PF_ALPHA_BYTE_INSTRUCTIONS
] = FALSE
;
404 SharedUserData
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] =
405 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE
);
406 SharedUserData
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] =
407 (Ke386CpuidExFlags
& X86_EXT_FEATURE_3DNOW
);
408 SharedUserData
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] =
409 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_TSC
);
410 SharedUserData
->ProcessorFeatures
[PF_PAE_ENABLED
] = Ke386PaeEnabled
;
411 SharedUserData
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] =
412 (Pcr
->PrcbData
.FeatureBits
& X86_FEATURE_SSE2
);