Fixed definition of KPCR_TIB to match W32API/NT5 defintion. Fixed bug in Makefile...
[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 PFN_TYPE PcrPages[MAXIMUM_PROCESSORS];
39 ULONG Ke386CpuidFlags, Ke386CpuidFlags2, Ke386CpuidExFlags;
40 ULONG Ke386Cpuid = 0x300;
41 ULONG Ke386CacheAlignment;
42 CHAR Ke386CpuidVendor[13] = {0,};
43 CHAR Ke386CpuidModel[49] = {0,};
44 ULONG Ke386L1CacheSize;
45 ULONG Ke386L2CacheSize;
46 BOOLEAN Ke386NoExecute = FALSE;
47 BOOLEAN Ke386Pae = FALSE;
48
49 /* FUNCTIONS *****************************************************************/
50
51 VOID INIT_FUNCTION STATIC
52 Ki386GetCpuId(VOID)
53 {
54 ULONG OrigFlags, Flags, FinalFlags;
55 ULONG MaxCpuidLevel;
56 ULONG Dummy, Ebx, Ecx, Edx;
57
58 Ke386CpuidFlags = Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
59 Ke386CacheAlignment = 32;
60
61 /* Try to toggle the id bit in eflags. */
62 __asm__ ("pushfl\n\t"
63 "popl %0\n\t"
64 : "=r" (OrigFlags));
65 Flags = OrigFlags ^ X86_EFLAGS_ID;
66 __asm__ ("pushl %1\n\t"
67 "popfl\n\t"
68 "pushfl\n\t"
69 "popl %0\n\t"
70 : "=r" (FinalFlags)
71 : "r" (Flags));
72 if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
73 {
74 /* No cpuid supported. */
75 return;
76 }
77
78 /* Get the vendor name and the maximum cpuid level supported. */
79 Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Ke386CpuidVendor[0], (PULONG)&Ke386CpuidVendor[8], (PULONG)&Ke386CpuidVendor[4]);
80 if (MaxCpuidLevel > 0)
81 {
82 /* Get the feature flags. */
83 Ki386Cpuid(1, &Ke386Cpuid, &Ebx, &Ke386CpuidFlags2, &Ke386CpuidFlags);
84 /* Get the cache alignment, if it is available */
85 if (Ke386CpuidFlags & (1<<19))
86 {
87 Ke386CacheAlignment = ((Ebx >> 8) & 0xff) * 8;
88 }
89 }
90
91 /* Get the maximum extended cpuid level supported. */
92 Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
93 if (MaxCpuidLevel > 0)
94 {
95 /* Get the extended feature flags. */
96 Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
97 }
98
99 /* Get the model name. */
100 if (MaxCpuidLevel >= 0x80000004)
101 {
102 PULONG v = (PULONG)&Ke386CpuidModel;
103 Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
104 Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
105 Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
106 }
107
108 /* Get the L1 cache size */
109 if (MaxCpuidLevel >= 0x80000005)
110 {
111 Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
112 Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
113 if ((Ecx & 0xff) > 0)
114 {
115 Ke386CacheAlignment = Ecx & 0xff;
116 }
117 }
118
119 /* Get the L2 cache size */
120 if (MaxCpuidLevel >= 0x80000006)
121 {
122 Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
123 Ke386L2CacheSize = Ecx >> 16;
124 }
125 }
126
127 VOID INIT_FUNCTION
128 KePrepareForApplicationProcessorInit(ULONG Id)
129 {
130 MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PcrPages[Id]);
131 KiGdtPrepareForApplicationProcessorInit(Id);
132 }
133
134 VOID
135 KeApplicationProcessorInit(VOID)
136 {
137 PKPCR KPCR;
138 ULONG Offset;
139
140 /*
141 * Create a PCR for this processor
142 */
143 Offset = InterlockedIncrement((LONG *)&PcrsAllocated) - 1;
144 KPCR = (PKPCR)(KPCR_BASE + (Offset * PAGE_SIZE));
145 MmCreateVirtualMappingForKernel((PVOID)KPCR,
146 PAGE_READWRITE,
147 &PcrPages[Offset],
148 1);
149 memset(KPCR, 0, PAGE_SIZE);
150 KPCR->ProcessorNumber = (UCHAR)Offset;
151 KPCR->Tib.Self = &KPCR->Tib;
152 KPCR->Irql = HIGH_LEVEL;
153
154 /* Mark the end of the exception handler list */
155 KPCR->Tib.ExceptionList = (PVOID)-1;
156
157 /*
158 * Initialize the GDT
159 */
160 KiInitializeGdt(KPCR);
161
162 /*
163 * It is now safe to process interrupts
164 */
165 KeLowerIrql(DISPATCH_LEVEL);
166
167 /*
168 * Initialize the TSS
169 */
170 Ki386ApplicationProcessorInitializeTSS();
171
172 /*
173 * Initialize a default LDT
174 */
175 Ki386InitializeLdt();
176
177 if (Ke386CpuidFlags & X86_FEATURE_PGE)
178 {
179 /* Enable global pages */
180 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
181 }
182
183 /* Enable PAE mode */
184 if (Ke386CpuidFlags & X86_FEATURE_PAE)
185 {
186 MiEnablePAE(NULL);
187 }
188
189 /* Now we can enable interrupts. */
190 Ke386EnableInterrupts();
191 }
192
193 VOID INIT_FUNCTION
194 KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
195 {
196 PKPCR KPCR;
197 BOOLEAN Pae = FALSE;
198 BOOLEAN NoExecute = FALSE;
199 PCHAR p1, p2;
200 extern USHORT KiBootGdt[];
201 extern KTSS KiBootTss;
202
203 KiCheckFPU();
204
205 KiInitializeGdt (NULL);
206 Ki386BootInitializeTSS();
207 KeInitExceptions ();
208 KeInitInterrupts ();
209
210 /*
211 * Initialize the initial PCR region. We can't allocate a page
212 * with MmAllocPage() here because MmInit1() has not yet been
213 * called, so we use a predefined page in low memory
214 */
215 KPCR = (PKPCR)KPCR_BASE;
216 memset(KPCR, 0, PAGE_SIZE);
217 KPCR->Self = (PKPCR)KPCR_BASE;
218 KPCR->Irql = HIGH_LEVEL;
219 KPCR->Tib.Self = &KPCR->Tib;
220 KPCR->GDT = KiBootGdt;
221 KPCR->IDT = (PUSHORT)KiIdt;
222 KPCR->TSS = &KiBootTss;
223 KPCR->ProcessorNumber = 0;
224 KiPcrInitDone = 1;
225 PcrsAllocated++;
226
227 /* Mark the end of the exception handler list */
228 KPCR->Tib.ExceptionList = (PVOID)-1;
229
230 Ki386InitializeLdt();
231
232 /* Get processor information. */
233 Ki386GetCpuId();
234
235 if (Ke386CpuidFlags & X86_FEATURE_PGE)
236 {
237 ULONG Flags;
238 /* Enable global pages */
239 Ke386SaveFlags(Flags);
240 Ke386DisableInterrupts();
241 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
242 Ke386RestoreFlags(Flags);
243 }
244
245 /* Search for pae and noexecute */
246 p1 = (PCHAR)KeLoaderBlock.CommandLine;
247 while(*p1 && (p2 = strchr(p1, '/')))
248 {
249 p2++;
250 if (!_strnicmp(p2, "PAE", 3))
251 {
252 if (p2[3] == ' ' || p2[3] == 0)
253 {
254 p2 += 3;
255 Pae = TRUE;
256 }
257 }
258 else if (!_strnicmp(p2, "NOEXECUTE", 9))
259 {
260 if (p2[9] == ' ' || p2[9] == '=' || p2[9] == 0)
261 {
262 p2 += 9;
263 NoExecute = TRUE;
264 }
265 }
266 p1 = p2;
267 }
268
269 /*
270 * FIXME:
271 * Make the detection of the noexecute feature more portable.
272 */
273 if(((Ke386Cpuid >> 8) & 0xf) == 0xf &&
274 0 == strcmp("AuthenticAMD", Ke386CpuidVendor))
275 {
276 if (NoExecute)
277 {
278 ULONG Flags, l, h;
279 Ke386SaveFlags(Flags);
280 Ke386DisableInterrupts();
281
282 Ke386Rdmsr(0xc0000080, l, h);
283 l |= (1 << 11);
284 Ke386Wrmsr(0xc0000080, l, h);
285 Ke386NoExecute = TRUE;
286 Ke386RestoreFlags(Flags);
287 }
288 }
289 else
290 {
291 NoExecute=FALSE;
292 }
293
294
295 /* Enable PAE mode */
296 if ((Pae && (Ke386CpuidFlags & X86_FEATURE_PAE)) || NoExecute)
297 {
298 MiEnablePAE((PVOID*)LastKernelAddress);
299 }
300 }
301
302 VOID INIT_FUNCTION
303 KeInit2(VOID)
304 {
305 KeInitDpc();
306 KeInitializeBugCheck();
307 KeInitializeDispatcher();
308 KeInitializeTimerImpl();
309
310 if (Ke386CpuidFlags & X86_FEATURE_PAE)
311 {
312 DPRINT1("CPU supports PAE mode\n");
313 if (Ke386Pae)
314 {
315 DPRINT1("CPU runs in PAE mode\n");
316 if (Ke386NoExecute)
317 {
318 DPRINT1("NoExecute is enabled\n");
319 }
320 }
321 else
322 {
323 DPRINT1("CPU doesn't run in PAE mode\n");
324 }
325 }
326 if (Ke386CpuidVendor[0])
327 {
328 DPRINT1("CPU Vendor: %s\n", Ke386CpuidVendor);
329 }
330 if (Ke386CpuidModel[0])
331 {
332 DPRINT1("CPU Model: %s\n", Ke386CpuidModel);
333 }
334
335 DPRINT1("Ke386CacheAlignment: %d\n", Ke386CacheAlignment);
336 if (Ke386L1CacheSize)
337 {
338 DPRINT1("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize);
339 }
340 if (Ke386L2CacheSize)
341 {
342 DPRINT1("Ke386L2CacheSize: %dkB\n", Ke386L2CacheSize);
343 }
344 }