Branch setupapi (again)
[reactos.git] / reactos / ntoskrnl / ke / i386 / kernel.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/kernel.c
22 * PURPOSE: Initializes the kernel
23 * PROGRAMMER: David Welch (welch@mcmail.com)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* GLOBALS *******************************************************************/
35
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;
46
47 /* FUNCTIONS *****************************************************************/
48
49 VOID INIT_FUNCTION STATIC
50 Ki386GetCpuId(VOID)
51 {
52 ULONG OrigFlags, Flags, FinalFlags;
53 ULONG MaxCpuidLevel;
54 ULONG Dummy, Eax, Ebx, Ecx, Edx;
55 PKPCR Pcr = KeGetCurrentKPCR();
56
57 Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
58 Ke386CacheAlignment = 32;
59
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))
66 {
67 /* No cpuid supported. */
68 Pcr->PrcbData.CpuID = FALSE;
69 Pcr->PrcbData.CpuType = 3;
70 return;
71 }
72 Pcr->PrcbData.CpuID = TRUE;
73
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)
77 {
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))
82 {
83 Ke386CacheAlignment = ((Ebx >> 8) & 0xff) * 8;
84 }
85 Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
86 Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
87 }
88 else
89 {
90 Pcr->PrcbData.CpuType = 4;
91 }
92
93 /* Get the maximum extended cpuid level supported. */
94 Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
95 if (MaxCpuidLevel > 0)
96 {
97 /* Get the extended feature flags. */
98 Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
99 }
100
101 /* Get the model name. */
102 if (MaxCpuidLevel >= 0x80000004)
103 {
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);
108 }
109
110 /* Get the L1 cache size */
111 if (MaxCpuidLevel >= 0x80000005)
112 {
113 Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
114 Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
115 if ((Ecx & 0xff) > 0)
116 {
117 Ke386CacheAlignment = Ecx & 0xff;
118 }
119 }
120
121 /* Get the L2 cache size */
122 if (MaxCpuidLevel >= 0x80000006)
123 {
124 Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
125 Pcr->L2CacheSize = Ecx >> 16;
126 }
127 }
128
129 VOID INIT_FUNCTION
130 KePrepareForApplicationProcessorInit(ULONG Id)
131 {
132 DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id);
133 PFN_TYPE PrcPfn;
134 PKPCR Pcr;
135 PKPCR BootPcr;
136
137 BootPcr = (PKPCR)KPCR_BASE;
138 Pcr = (PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE);
139
140 MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PrcPfn);
141 MmCreateVirtualMappingForKernel((PVOID)Pcr,
142 PAGE_READWRITE,
143 &PrcPfn,
144 1);
145 /*
146 * Create a PCR for this processor
147 */
148 memset(Pcr, 0, PAGE_SIZE);
149 Pcr->ProcessorNumber = Id;
150 Pcr->Tib.Self = &Pcr->Tib;
151 Pcr->Self = Pcr;
152 Pcr->Irql = SYNCH_LEVEL;
153
154 Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz;
155 Pcr->StallScaleFactor = BootPcr->StallScaleFactor;
156
157 /* Mark the end of the exception handler list */
158 Pcr->Tib.ExceptionList = (PVOID)-1;
159
160 KiGdtPrepareForApplicationProcessorInit(Id);
161 }
162
163 VOID
164 KeApplicationProcessorInit(VOID)
165 {
166 ULONG Offset;
167 PKPCR Pcr;
168
169 DPRINT("KeApplicationProcessorInit()\n");
170
171 if (Ke386GlobalPagesEnabled)
172 {
173 /* Enable global pages */
174 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
175 }
176
177
178 Offset = InterlockedIncrementUL(&PcrsAllocated) - 1;
179 Pcr = (PKPCR)((ULONG_PTR)KPCR_BASE + Offset * PAGE_SIZE);
180
181 /*
182 * Initialize the GDT
183 */
184 KiInitializeGdt(Pcr);
185
186 /* Get processor information. */
187 Ki386GetCpuId();
188
189 /* Check FPU/MMX/SSE support. */
190 KiCheckFPU();
191
192 KeInitDpc(Pcr);
193
194 /*
195 * It is now safe to process interrupts
196 */
197 KeLowerIrql(DISPATCH_LEVEL);
198
199 /*
200 * Initialize the TSS
201 */
202 Ki386ApplicationProcessorInitializeTSS();
203
204 /*
205 * Initialize a default LDT
206 */
207 Ki386InitializeLdt();
208
209 /* Now we can enable interrupts. */
210 Ke386EnableInterrupts();
211 }
212
213 VOID INIT_FUNCTION
214 KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
215 {
216 PKPCR KPCR;
217 BOOLEAN Pae = FALSE;
218 BOOLEAN NoExecute = FALSE;
219 PCHAR p1, p2;
220 extern USHORT KiBootGdt[];
221 extern KTSS KiBootTss;
222
223 /*
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
227 */
228
229 KPCR = (PKPCR)KPCR_BASE;
230 memset(KPCR, 0, PAGE_SIZE);
231 KPCR->Self = KPCR;
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;
238 KiPcrInitDone = 1;
239 PcrsAllocated++;
240
241 KiInitializeGdt (NULL);
242 Ki386BootInitializeTSS();
243 Ki386InitializeLdt();
244
245 /* Get processor information. */
246 Ki386GetCpuId();
247
248 /* Check FPU/MMX/SSE support. */
249 KiCheckFPU();
250
251 /* Mark the end of the exception handler list */
252 KPCR->Tib.ExceptionList = (PVOID)-1;
253
254 KeInitDpc(KPCR);
255
256 KeInitExceptions ();
257 KeInitInterrupts ();
258
259 if (KPCR->PrcbData.FeatureBits & X86_FEATURE_PGE)
260 {
261 ULONG Flags;
262 /* Enable global pages */
263 Ke386GlobalPagesEnabled = TRUE;
264 Ke386SaveFlags(Flags);
265 Ke386DisableInterrupts();
266 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
267 Ke386RestoreFlags(Flags);
268 }
269
270 /* Search for pae and noexecute */
271 p1 = (PCHAR)KeLoaderBlock.CommandLine;
272 while(*p1 && (p2 = strchr(p1, '/')))
273 {
274 p2++;
275 if (!_strnicmp(p2, "PAE", 3))
276 {
277 if (p2[3] == ' ' || p2[3] == 0)
278 {
279 p2 += 3;
280 Pae = TRUE;
281 }
282 }
283 else if (!_strnicmp(p2, "NOEXECUTE", 9))
284 {
285 if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
286 {
287 p2 += 9;
288 NoExecute = TRUE;
289 }
290 }
291 p1 = p2;
292 }
293
294 /*
295 * FIXME:
296 * Make the detection of the noexecute feature more portable.
297 */
298 if(KPCR->PrcbData.CpuType == 0xf &&
299 RtlCompareMemory("AuthenticAMD", KPCR->PrcbData.VendorString, 12) == 12)
300 {
301 if (NoExecute)
302 {
303 ULONG Flags, l, h;
304 Ke386SaveFlags(Flags);
305 Ke386DisableInterrupts();
306
307 Ke386Rdmsr(0xc0000080, l, h);
308 l |= (1 << 11);
309 Ke386Wrmsr(0xc0000080, l, h);
310 Ke386NoExecute = TRUE;
311 Ke386RestoreFlags(Flags);
312 }
313 }
314 else
315 {
316 NoExecute=FALSE;
317 }
318
319
320 /* Enable PAE mode */
321 if ((Pae && (KPCR->PrcbData.FeatureBits & X86_FEATURE_PAE)) || NoExecute)
322 {
323 MiEnablePAE((PVOID*)LastKernelAddress);
324 Ke386PaeEnabled = TRUE;
325 }
326 }
327
328 VOID INIT_FUNCTION
329 KeInit2(VOID)
330 {
331 PKPCR Pcr = KeGetCurrentKPCR();
332
333 KeInitializeBugCheck();
334 KeInitializeDispatcher();
335 KeInitializeTimerImpl();
336
337 if (Pcr->PrcbData.FeatureBits & X86_FEATURE_PAE)
338 {
339 DPRINT("CPU supports PAE mode\n");
340 if (Ke386Pae)
341 {
342 DPRINT("CPU runs in PAE mode\n");
343 if (Ke386NoExecute)
344 {
345 DPRINT("NoExecute is enabled\n");
346 }
347 }
348 else
349 {
350 DPRINT("CPU doesn't run in PAE mode\n");
351 }
352 }
353 if ((Pcr->PrcbData.FeatureBits & (X86_FEATURE_FXSR | X86_FEATURE_MMX | X86_FEATURE_SSE | X86_FEATURE_SSE2)) ||
354 (Ke386CpuidFlags2 & X86_EXT_FEATURE_SSE3))
355 {
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" : ""));
362 }
363 if (Ke386GetCr4() & X86_CR4_OSFXSR)
364 {
365 DPRINT("SSE enabled.\n");
366 }
367 if (Ke386GetCr4() & X86_CR4_OSXMMEXCPT)
368 {
369 DPRINT("Unmasked SIMD exceptions enabled.\n");
370 }
371 if (Pcr->PrcbData.VendorString[0])
372 {
373 DPRINT("CPU Vendor: %s\n", Pcr->PrcbData.VendorString);
374 }
375 if (Ke386CpuidModel[0])
376 {
377 DPRINT("CPU Model: %s\n", Ke386CpuidModel);
378 }
379
380 DPRINT("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
381 if (Ke386L1CacheSize)
382 {
383 DPRINT("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
384 }
385 if (Pcr->L2CacheSize)
386 {
387 DPRINT("Ke386L2CacheSize: %dkB\n", Pcr->L2CacheSize);
388 }
389 }
390
391 VOID INIT_FUNCTION
392 Ki386SetProcessorFeatures(VOID)
393 {
394 PKPCR Pcr = KeGetCurrentKPCR();
395
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);
413 }