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 + -
显示快捷键?