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 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
;
49 /* FUNCTIONS *****************************************************************/
51 VOID INIT_FUNCTION STATIC
54 ULONG OrigFlags
, Flags
, FinalFlags
;
56 ULONG Dummy
, Ebx
, Ecx
, Edx
;
58 Ke386CpuidFlags
= Ke386CpuidFlags2
= Ke386CpuidExFlags
= 0;
59 Ke386CacheAlignment
= 32;
61 /* Try to toggle the id bit in eflags. */
65 Flags
= OrigFlags
^ X86_EFLAGS_ID
;
66 __asm__ ("pushl %1\n\t"
72 if ((OrigFlags
& X86_EFLAGS_ID
) == (FinalFlags
& X86_EFLAGS_ID
))
74 /* No cpuid supported. */
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)
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))
87 Ke386CacheAlignment
= ((Ebx
>> 8) & 0xff) * 8;
91 /* Get the maximum extended cpuid level supported. */
92 Ki386Cpuid(0x80000000, &MaxCpuidLevel
, &Dummy
, &Dummy
, &Dummy
);
93 if (MaxCpuidLevel
> 0)
95 /* Get the extended feature flags. */
96 Ki386Cpuid(0x80000001, &Dummy
, &Dummy
, &Dummy
, &Ke386CpuidExFlags
);
99 /* Get the model name. */
100 if (MaxCpuidLevel
>= 0x80000004)
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);
108 /* Get the L1 cache size */
109 if (MaxCpuidLevel
>= 0x80000005)
111 Ki386Cpuid(0x80000005, &Dummy
, &Dummy
, &Ecx
, &Edx
);
112 Ke386L1CacheSize
= (Ecx
>> 24)+(Edx
>> 24);
113 if ((Ecx
& 0xff) > 0)
115 Ke386CacheAlignment
= Ecx
& 0xff;
119 /* Get the L2 cache size */
120 if (MaxCpuidLevel
>= 0x80000006)
122 Ki386Cpuid(0x80000006, &Dummy
, &Dummy
, &Ecx
, &Dummy
);
123 Ke386L2CacheSize
= Ecx
>> 16;
128 KePrepareForApplicationProcessorInit(ULONG Id
)
130 MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &PcrPages
[Id
]);
131 KiGdtPrepareForApplicationProcessorInit(Id
);
135 KeApplicationProcessorInit(VOID
)
141 * Create a PCR for this processor
143 Offset
= InterlockedIncrement((LONG
*)&PcrsAllocated
) - 1;
144 KPCR
= (PKPCR
)(KPCR_BASE
+ (Offset
* PAGE_SIZE
));
145 MmCreateVirtualMappingForKernel((PVOID
)KPCR
,
149 memset(KPCR
, 0, PAGE_SIZE
);
150 KPCR
->ProcessorNumber
= (UCHAR
)Offset
;
151 KPCR
->Tib
.Self
= &KPCR
->Tib
;
152 KPCR
->Irql
= HIGH_LEVEL
;
154 /* Mark the end of the exception handler list */
155 KPCR
->Tib
.ExceptionList
= (PVOID
)-1;
160 KiInitializeGdt(KPCR
);
163 * It is now safe to process interrupts
165 KeLowerIrql(DISPATCH_LEVEL
);
170 Ki386ApplicationProcessorInitializeTSS();
173 * Initialize a default LDT
175 Ki386InitializeLdt();
177 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
179 /* Enable global pages */
180 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
183 /* Enable PAE mode */
184 if (Ke386CpuidFlags
& X86_FEATURE_PAE
)
189 /* Now we can enable interrupts. */
190 Ke386EnableInterrupts();
194 KeInit1(PCHAR CommandLine
, PULONG LastKernelAddress
)
198 BOOLEAN NoExecute
= FALSE
;
200 extern USHORT KiBootGdt
[];
201 extern KTSS KiBootTss
;
205 KiInitializeGdt (NULL
);
206 Ki386BootInitializeTSS();
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
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;
227 /* Mark the end of the exception handler list */
228 KPCR
->Tib
.ExceptionList
= (PVOID
)-1;
230 Ki386InitializeLdt();
232 /* Get processor information. */
235 if (Ke386CpuidFlags
& X86_FEATURE_PGE
)
238 /* Enable global pages */
239 Ke386SaveFlags(Flags
);
240 Ke386DisableInterrupts();
241 Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE
);
242 Ke386RestoreFlags(Flags
);
245 /* Search for pae and noexecute */
246 p1
= (PCHAR
)KeLoaderBlock
.CommandLine
;
247 while(*p1
&& (p2
= strchr(p1
, '/')))
250 if (!_strnicmp(p2
, "PAE", 3))
252 if (p2
[3] == ' ' || p2
[3] == 0)
258 else if (!_strnicmp(p2
, "NOEXECUTE", 9))
260 if (p2
[9] == ' ' || p2
[9] == '=' || p2
[9] == 0)
271 * Make the detection of the noexecute feature more portable.
273 if(((Ke386Cpuid
>> 8) & 0xf) == 0xf &&
274 0 == strcmp("AuthenticAMD", Ke386CpuidVendor
))
279 Ke386SaveFlags(Flags
);
280 Ke386DisableInterrupts();
282 Ke386Rdmsr(0xc0000080, l
, h
);
284 Ke386Wrmsr(0xc0000080, l
, h
);
285 Ke386NoExecute
= TRUE
;
286 Ke386RestoreFlags(Flags
);
295 /* Enable PAE mode */
296 if ((Pae
&& (Ke386CpuidFlags
& X86_FEATURE_PAE
)) || NoExecute
)
298 MiEnablePAE((PVOID
*)LastKernelAddress
);
306 KeInitializeBugCheck();
307 KeInitializeDispatcher();
308 KeInitializeTimerImpl();
310 if (Ke386CpuidFlags
& X86_FEATURE_PAE
)
312 DPRINT1("CPU supports PAE mode\n");
315 DPRINT1("CPU runs in PAE mode\n");
318 DPRINT1("NoExecute is enabled\n");
323 DPRINT1("CPU doesn't run in PAE mode\n");
326 if (Ke386CpuidVendor
[0])
328 DPRINT1("CPU Vendor: %s\n", Ke386CpuidVendor
);
330 if (Ke386CpuidModel
[0])
332 DPRINT1("CPU Model: %s\n", Ke386CpuidModel
);
335 DPRINT1("Ke386CacheAlignment: %d\n", Ke386CacheAlignment
);
336 if (Ke386L1CacheSize
)
338 DPRINT1("Ke386L1CacheSize: %dkB\n", Ke386L1CacheSize
);
340 if (Ke386L2CacheSize
)
342 DPRINT1("Ke386L2CacheSize: %dkB\n", Ke386L2CacheSize
);