kernel.c
来自「一个类似windows」· C语言 代码 · 共 599 行 · 第 1/2 页
C
599 行
/* $Id: kernel.c 21252 2006-03-08 20:03:59Z audit $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/i386/kernel.c
* PURPOSE: Initializes the kernel
*
* PROGRAMMERS: David Welch (welch@mcmail.com)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
ULONG KiPcrInitDone = 0;
static ULONG PcrsAllocated = 0;
static ULONG Ke386CpuidFlags2, Ke386CpuidExFlags, Ke386CpuidExMisc;
ULONG Ke386CacheAlignment;
CHAR Ke386CpuidModel[49] = {0,};
ULONG Ke386L1CacheSize;
BOOLEAN Ke386NoExecute = FALSE;
BOOLEAN Ke386Pae = FALSE;
BOOLEAN Ke386GlobalPagesEnabled = FALSE;
ULONG KiFastSystemCallDisable = 1;
ULONG KeI386NpxPresent = 0;
ULONG KeI386XMMIPresent = 0;
ULONG KeI386FxsrPresent = 0;
extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
extern ULONG IdleProcessorMask;
extern KIDTENTRY KiIdt[256];
static VOID INIT_FUNCTION Ki386GetCpuId(VOID);
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, Ki386GetCpuId)
#pragma alloc_text(INIT, KeCreateApplicationProcessorIdleThread)
#pragma alloc_text(INIT, KePrepareForApplicationProcessorInit)
#pragma alloc_text(INIT, KeInit1)
#pragma alloc_text(INIT, KeInit2)
#pragma alloc_text(INIT, Ki386SetProcessorFeatures)
#endif
/* FUNCTIONS *****************************************************************/
static VOID INIT_FUNCTION
Ki386GetCpuId(VOID)
{
ULONG OrigFlags, Flags, FinalFlags;
ULONG MaxCpuidLevel;
ULONG Dummy, Eax, Ecx, Edx;
PKIPCR Pcr = (PKIPCR)KeGetCurrentKPCR();
Ke386CpuidFlags2 = Ke386CpuidExFlags = 0;
Ke386CacheAlignment = 32;
/* Try to toggle the id bit in eflags. */
Ke386SaveFlags(OrigFlags);
Flags = OrigFlags ^ X86_EFLAGS_ID;
Ke386RestoreFlags(Flags);
Ke386SaveFlags(FinalFlags);
Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = 1;
Pcr->PrcbData.InitialApicId = 0xff;
if ((OrigFlags & X86_EFLAGS_ID) == (FinalFlags & X86_EFLAGS_ID))
{
/* No cpuid supported. */
Pcr->PrcbData.CpuID = FALSE;
Pcr->PrcbData.CpuType = 3;
return;
}
Pcr->PrcbData.CpuID = TRUE;
/* Get the vendor name and the maximum cpuid level supported. */
Ki386Cpuid(0, &MaxCpuidLevel, (PULONG)&Pcr->PrcbData.VendorString[0], (PULONG)&Pcr->PrcbData.VendorString[8], (PULONG)&Pcr->PrcbData.VendorString[4]);
if (MaxCpuidLevel > 0)
{
/* Get the feature flags. */
Ki386Cpuid(1, &Eax, &Ke386CpuidExMisc, &Ke386CpuidFlags2, &Pcr->PrcbData.FeatureBits);
DPRINT ("Model: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 4) & 0xf) | ((Eax >> 12) & 0xf0) : (Eax >> 4) & 0xf);
DPRINT ("Family: %x\n", (Eax & 0xf00) == 0xf00 ? ((Eax >> 8) & 0xf) + ((Eax >> 20) & 0xff) : (Eax >> 8) & 0xf);
/* Get the cache alignment, if it is available */
if (Pcr->PrcbData.FeatureBits & (1<<19))
{
Ke386CacheAlignment = ((Ke386CpuidExMisc >> 8) & 0xff) * 8;
}
Pcr->PrcbData.CpuType = (Eax >> 8) & 0xf;
Pcr->PrcbData.CpuStep = (Eax & 0xf) | ((Eax << 4) & 0xf00);
Pcr->PrcbData.InitialApicId = (Ke386CpuidExMisc >> 24) & 0xff;
/* detect Hyper-Threading on Pentium 4 CPUs or later */
if ((Pcr->PrcbData.CpuType == 0xf || (Eax & 0x0f00000)) &&
!strncmp(Pcr->PrcbData.VendorString, "GenuineIntel", 12) &&
Pcr->PrcbData.FeatureBits & X86_FEATURE_HT)
{
Pcr->PrcbData.LogicalProcessorsPerPhysicalProcessor = (Ke386CpuidExMisc >> 16) & 0xff;
}
}
else
{
Pcr->PrcbData.CpuType = 4;
}
/* Get the maximum extended cpuid level supported. */
Ki386Cpuid(0x80000000, &MaxCpuidLevel, &Dummy, &Dummy, &Dummy);
if (MaxCpuidLevel > 0)
{
/* Get the extended feature flags. */
Ki386Cpuid(0x80000001, &Dummy, &Dummy, &Dummy, &Ke386CpuidExFlags);
}
/* Get the model name. */
if (MaxCpuidLevel >= 0x80000004)
{
PULONG v = (PULONG)Ke386CpuidModel;
Ki386Cpuid(0x80000002, v, v + 1, v + 2, v + 3);
Ki386Cpuid(0x80000003, v + 4, v + 5, v + 6, v + 7);
Ki386Cpuid(0x80000004, v + 8, v + 9, v + 10, v + 11);
}
/* Get the L1 cache size */
if (MaxCpuidLevel >= 0x80000005)
{
Ki386Cpuid(0x80000005, &Dummy, &Dummy, &Ecx, &Edx);
Ke386L1CacheSize = (Ecx >> 24)+(Edx >> 24);
if ((Ecx & 0xff) > 0)
{
Ke386CacheAlignment = Ecx & 0xff;
}
}
/* Get the L2 cache size */
if (MaxCpuidLevel >= 0x80000006)
{
Ki386Cpuid(0x80000006, &Dummy, &Dummy, &Ecx, &Dummy);
Pcr->L2CacheSize = Ecx >> 16;
}
}
VOID
KeApplicationProcessorInitDispatcher(VOID)
{
KIRQL oldIrql;
oldIrql = KeAcquireDispatcherDatabaseLock();
IdleProcessorMask |= (1 << KeGetCurrentProcessorNumber());
KeReleaseDispatcherDatabaseLock(oldIrql);
}
VOID
INIT_FUNCTION
KeCreateApplicationProcessorIdleThread(ULONG Id)
{
PETHREAD IdleThread;
PKPRCB Prcb = ((PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE))->Prcb;
PsInitializeIdleOrFirstThread(PsIdleProcess,
&IdleThread,
NULL,
KernelMode,
FALSE);
IdleThread->Tcb.State = Running;
IdleThread->Tcb.FreezeCount = 0;
IdleThread->Tcb.Affinity = 1 << Id;
IdleThread->Tcb.UserAffinity = 1 << Id;
IdleThread->Tcb.Priority = LOW_PRIORITY;
IdleThread->Tcb.BasePriority = LOW_PRIORITY;
Prcb->IdleThread = &IdleThread->Tcb;
Prcb->CurrentThread = &IdleThread->Tcb;
Ki386InitialStackArray[Id] = (PVOID)IdleThread->Tcb.StackLimit;
DPRINT("IdleThread for Processor %d has PID %d\n",
Id, IdleThread->Cid.UniqueThread);
}
VOID
INIT_FUNCTION
NTAPI
KePrepareForApplicationProcessorInit(ULONG Id)
{
PFN_TYPE PrcPfn;
PKIPCR Pcr;
PKIPCR BootPcr;
DPRINT("KePrepareForApplicationProcessorInit(Id %d)\n", Id);
BootPcr = (PKIPCR)KPCR_BASE;
Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE);
MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PrcPfn);
MmCreateVirtualMappingForKernel((PVOID)Pcr,
PAGE_READWRITE,
&PrcPfn,
1);
/*
* Create a PCR for this processor
*/
memset(Pcr, 0, PAGE_SIZE);
Pcr->Number = Id;
Pcr->SetMember = 1 << Id;
Pcr->NtTib.Self = &Pcr->NtTib;
Pcr->Self = (PKPCR)Pcr;
Pcr->Prcb = &Pcr->PrcbData;
Pcr->Irql = SYNCH_LEVEL;
Pcr->PrcbData.SetMember = 1 << Id;
Pcr->PrcbData.MHz = BootPcr->PrcbData.MHz;
Pcr->StallScaleFactor = BootPcr->StallScaleFactor;
/* Mark the end of the exception handler list */
Pcr->NtTib.ExceptionList = (PVOID)-1;
KiGdtPrepareForApplicationProcessorInit(Id);
KeActiveProcessors |= 1 << Id;
}
VOID
NTAPI
KeApplicationProcessorInit(VOID)
{
ULONG Offset;
PKIPCR Pcr;
DPRINT("KeApplicationProcessorInit()\n");
if (Ke386GlobalPagesEnabled)
{
/* Enable global pages */
Ke386SetCr4(Ke386GetCr4() | X86_CR4_PGE);
}
Offset = InterlockedIncrementUL(&PcrsAllocated) - 1;
Pcr = (PKIPCR)((ULONG_PTR)KPCR_BASE + Offset * PAGE_SIZE);
/*
* Initialize the GDT
*/
KiInitializeGdt((PKPCR)Pcr);
/* Get processor information. */
Ki386GetCpuId();
/* Check FPU/MMX/SSE support. */
KiCheckFPU();
KeInitDpc(Pcr->Prcb);
if (Pcr->PrcbData.FeatureBits & X86_FEATURE_SYSCALL)
{
extern void KiFastCallEntry(void);
/* CS Selector of the target segment. */
Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
/* Target ESP. */
Ke386Wrmsr(0x175, 0, 0);
/* Target EIP. */
Ke386Wrmsr(0x176, (ULONG_PTR)KiFastCallEntry, 0);
}
/*
* It is now safe to process interrupts
*/
KeLowerIrql(DISPATCH_LEVEL);
/*
* Initialize the TSS
*/
Ki386ApplicationProcessorInitializeTSS();
/*
* Initialize a default LDT
*/
Ki386InitializeLdt();
/* Now we can enable interrupts. */
Ke386EnableInterrupts();
}
VOID
INIT_FUNCTION
NTAPI
KeInit1(PCHAR CommandLine, PULONG LastKernelAddress)
{
PKIPCR KPCR;
BOOLEAN Pae = FALSE;
BOOLEAN NoExecute = FALSE;
PCHAR p1, p2;
extern USHORT KiBootGdt[];
extern KTSS KiBootTss;
/*
* Initialize the initial PCR region. We can't allocate a page
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?