⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apic.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
    * FIXME:
    *   This works only up to 8 CPU's
    */
   tmp |= (1 << (KeGetCurrentProcessorNumber() + 24));
   APICWrite(APIC_LDR, tmp);


   DPRINT1("CPU%d:\n", CPU);
   DPRINT1("  Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID)));
   DPRINT1("  Logical APIC id:  %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR)));
   DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR));
   DPRINT1("%d\n", CPUMap[CPU].APICId);

   /* Accept only higher interrupts */
   APICWrite(APIC_TPR, 0xef);

   /* Enable local APIC */
   tmp = APICRead(APIC_SIVR);
   tmp &= ~0xff;
   tmp |= APIC_SIVR_ENABLE;

#if 0
   tmp &= ~APIC_SIVR_FOCUS;
#else
   tmp |= APIC_SIVR_FOCUS;
#endif

  /* Set spurious interrupt vector */
  tmp |= SPURIOUS_VECTOR;
  APICWrite(APIC_SIVR, tmp);

  /*
   * Set up LVT0, LVT1:
   *
   * set up through-local-APIC on the BP's LINT0. This is not
   * strictly necessery in pure symmetric-IO mode, but sometimes
   * we delegate interrupts to the 8259A.
   */
  tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED;
  if (CPU == BootCPU && (APICMode == amPIC || !tmp)) 
  {
     tmp = APIC_DM_EXTINT;
     DPRINT1("enabled ExtINT on CPU#%d\n", CPU);
  } 
  else 
  {
     tmp = APIC_DM_EXTINT | APIC_LVT_MASKED;
     DPRINT1("masked ExtINT on CPU#%d\n", CPU);
  }
  APICWrite(APIC_LINT0, tmp);

  /*
   * Only the BSP should see the LINT1 NMI signal, obviously.
   */
  if (CPU == BootCPU)
  {
     tmp = APIC_DM_NMI;
  }
  else
  {
     tmp = APIC_DM_NMI | APIC_LVT_MASKED;
  }
  if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 
  {
     /* 82489DX */
     tmp |= APIC_LVT_LEVEL_TRIGGER;
  }
  APICWrite(APIC_LINT1, tmp);

  if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 
  {	
     /* !82489DX */
     if (APICGetMaxLVT() > 3) 
     {
	/* Due to the Pentium erratum 3AP */
	APICWrite(APIC_ESR, 0);
     }

     tmp = APICRead(APIC_ESR);
     DPRINT("ESR value before enabling vector: 0x%X\n", tmp);

     /* Enable sending errors */
     tmp = ERROR_VECTOR;
     APICWrite(APIC_LVT3, tmp);

     /*
      * Spec says clear errors after enabling vector
      */
     if (APICGetMaxLVT() > 3)
     {
        APICWrite(APIC_ESR, 0);
     }
     tmp = APICRead(APIC_ESR);
     DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
  }
}
#ifdef CONFIG_SMP
VOID APICSyncArbIDs(VOID)
{
   ULONG i, tmp;

   /* Wait up to 100ms for the APIC to become ready */
   for (i = 0; i < 10000; i++) 
   {
      tmp = APICRead(APIC_ICR0);
      /* Check Delivery Status */
      if ((tmp & APIC_ICR0_DS) == 0)
         break;
      KeStallExecutionProcessor(10);
   }

   if (i == 10000) 
   {
      DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
   }

   DPRINT("Synchronizing Arb IDs.\n");
   APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
}
#endif

VOID MpsErrorHandler(VOID)
{
  ULONG tmp1, tmp2;

  APICDump();

  tmp1 = APICRead(APIC_ESR);
  APICWrite(APIC_ESR, 0);
  tmp2 = APICRead(APIC_ESR);
  DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);

  /*
   * Acknowledge the interrupt
   */
  APICSendEOI();

  /* Here is what the APIC error bits mean:
   *   0: Send CS error
   *   1: Receive CS error
   *   2: Send accept error
   *   3: Receive accept error
   *   4: Reserved
   *   5: Send illegal vector
   *   6: Received illegal vector
   *   7: Illegal register address
   */
  DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
  for (;;);
}

VOID MpsSpuriousHandler(VOID)
{
  ULONG tmp;

  DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
  
  tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1));
  if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f)))
  {
      APICSendEOI();
      return;
  }
#if 0
  /* No need to send EOI here */
  APICDump();
#endif
}

#ifdef CONFIG_SMP
VOID MpsIpiHandler(VOID)
{
   KIRQL oldIrql;

   HalBeginSystemInterrupt(IPI_LEVEL,
                           IPI_VECTOR, 
			   &oldIrql);
   _enable();
#if 0
   DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n", 
            __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
#endif   

   KiIpiServiceRoutine(NULL, NULL);

#if 0
   DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber());
#endif

   _disable();
   HalEndSystemInterrupt(oldIrql, 0);
}
#endif

VOID
MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
			   PKTRAP_FRAME TrapFrame)
{
   TrapFrame->SegGs     = (USHORT)IrqTrapFrame->Gs;
   TrapFrame->SegFs     = (USHORT)IrqTrapFrame->Fs;
   TrapFrame->SegEs     = (USHORT)IrqTrapFrame->Es;
   TrapFrame->SegDs     = (USHORT)IrqTrapFrame->Ds;
   TrapFrame->Eax    = IrqTrapFrame->Eax;
   TrapFrame->Ecx    = IrqTrapFrame->Ecx;
   TrapFrame->Edx    = IrqTrapFrame->Edx;
   TrapFrame->Ebx    = IrqTrapFrame->Ebx;
   TrapFrame->HardwareEsp    = IrqTrapFrame->Esp;
   TrapFrame->Ebp    = IrqTrapFrame->Ebp;
   TrapFrame->Esi    = IrqTrapFrame->Esi;
   TrapFrame->Edi    = IrqTrapFrame->Edi;
   TrapFrame->Eip    = IrqTrapFrame->Eip;
   TrapFrame->SegCs     = IrqTrapFrame->Cs;
   TrapFrame->EFlags = IrqTrapFrame->Eflags;
}

VOID
MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
{
   KIRQL oldIrql;
   KTRAP_FRAME KernelTrapFrame;
#if 0
   ULONG CPU;
   static ULONG Count[MAX_CPU] = {0,};
#endif
   HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR, 
                           PROFILE_LEVEL, 
			   &oldIrql);
   _enable();

#if 0
   CPU = ThisCPU();
   if ((Count[CPU] % 100) == 0)
   {
     DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr());
   }
   Count[CPU]++;
#endif

   /* FIXME: SMP is totally broken */
   MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
   if (KeGetCurrentProcessorNumber() == 0)
   {
      //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
   }
   else
   {
      //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
   }

   _disable();
   HalEndSystemInterrupt (oldIrql, 0);
}

VOID APICSetupLVTT(ULONG ClockTicks)
{
   ULONG tmp;

   tmp = GET_APIC_VERSION(APICRead(APIC_VER));
   if (!APIC_INTEGRATED(tmp))
   {
      tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;;
   }
   else
   {
      /* Periodic timer */
      tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;;
   }
   APICWrite(APIC_LVTT, tmp);

   tmp = APICRead(APIC_TDCR);
   tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV);
   tmp |= APIC_TDCR_16;
   APICWrite(APIC_TDCR, tmp);
   APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
}

VOID 
APICCalibrateTimer(ULONG CPU)
{
   ULARGE_INTEGER t1, t2;
   LONG tt1, tt2;
   BOOLEAN TSCPresent;

   DPRINT("Calibrating APIC timer for CPU %d\n", CPU);

   APICSetupLVTT(1000000000);

   TSCPresent = ((PKIPCR)KeGetPcr())->PrcbData.FeatureBits & KF_RDTSC ? TRUE : FALSE;

   /*
    * The timer chip counts down to zero. Let's wait
    * for a wraparound to start exact measurement:
    * (the current tick might have been already half done)
    */
   //WaitFor8254Wraparound();

   /*
    * We wrapped around just now. Let's start
    */
   if (TSCPresent)
   {
      t1.QuadPart = (LONGLONG)__rdtsc();
   }
   tt1 = APICRead(APIC_CCRT);

   //WaitFor8254Wraparound();


   tt2 = APICRead(APIC_CCRT);
   if (TSCPresent)
   {
      t2.QuadPart = (LONGLONG)__rdtsc();
      CPUMap[CPU].CoreSpeed = (HZ * (t2.QuadPart - t1.QuadPart));
      DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
	     CPUMap[CPU].CoreSpeed/1000000,
	     CPUMap[CPU].CoreSpeed%1000000);
      ((PKIPCR)KeGetPcr())->PrcbData.MHz = CPUMap[CPU].CoreSpeed/1000000;
   }

   CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR);

   /* Setup timer for normal operation */
// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100);    // 100ns
   APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000);  // 10ms
// APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms

   DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
	  CPUMap[CPU].BusSpeed/1000000,
	  CPUMap[CPU].BusSpeed%1000000);
}

VOID 
SetInterruptGate(ULONG index, ULONG address)
{
  KIDTENTRY *idt;
  KIDT_ACCESS Access;

  /* Set the IDT Access Bits */
  Access.Reserved = 0;
  Access.Present = 1;
  Access.Dpl = 0; /* Kernel-Mode */
  Access.SystemSegmentFlag = 0;
  Access.SegmentType = I386_INTERRUPT_GATE;
  
  idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY));
  idt->Offset = address & 0xffff;
  idt->Selector = KGDT_R0_CODE;
  idt->Access = Access.Value;
  idt->ExtendedOffset = address >> 16;
}

VOID HaliInitBSP(VOID)
{
#ifdef CONFIG_SMP
   PUSHORT ps;
#endif

   static BOOLEAN BSPInitialized = FALSE;

   /* Only initialize the BSP once */
   if (BSPInitialized)
   {
      KEBUGCHECK(0);
      return;
   }

   BSPInitialized = TRUE;

   /* Setup interrupt handlers */
   SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG)MpsTimerInterrupt);
   SetInterruptGate(ERROR_VECTOR, (ULONG)MpsErrorInterrupt);
   SetInterruptGate(SPURIOUS_VECTOR, (ULONG)MpsSpuriousInterrupt);
#ifdef CONFIG_SMP
   SetInterruptGate(IPI_VECTOR, (ULONG)MpsIpiInterrupt);
#endif
   DPRINT("APIC is mapped at 0x%X\n", APICBase);

   if (VerifyLocalAPIC()) 
   {
      DPRINT("APIC found\n");
   } 
   else 
   {
      DPRINT("No APIC found\n");
      KEBUGCHECK(0);
   }

   if (APICMode == amPIC) 
   {
      EnableApicMode();
   }

   APICSetup();

#ifdef CONFIG_SMP
   /* BIOS data segment */
   BIOSBase = (PULONG)BIOS_AREA;
   
   /* Area for communicating with the APs */
   CommonBase = (PULONG)COMMON_AREA;
 
   /* Copy bootstrap code to common area */
   memcpy((PVOID)((ULONG)CommonBase + PAGE_SIZE),
	  &APstart,
	  (ULONG)&APend - (ULONG)&APstart + 1);

   /* Set shutdown code */
   CMOS_WRITE(0xF, 0xA);

   /* Set warm reset vector */
   ps = (PUSHORT)((ULONG)BIOSBase + 0x467);
   *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
 
   ps = (PUSHORT)((ULONG)BIOSBase + 0x469);
   *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
#endif

   /* Calibrate APIC timer */
   APICCalibrateTimer(BootCPU);
}

#ifdef CONFIG_SMP
VOID
HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack)
{
   ULONG tmp, maxlvt;
   PCOMMON_AREA_INFO Common;
   ULONG StartupCount;
   ULONG i, j;
   ULONG DeliveryStatus = 0;
   ULONG AcceptStatus = 0;

   if (Cpu >= MAX_CPU ||
       Cpu >= CPUCount ||
       OnlineCPUs & (1 << Cpu))
   {
     KEBUGCHECK(0);
   }
   DPRINT1("Attempting to boot CPU %d\n", Cpu);

   /* Send INIT IPI */

   APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT);
 
   KeStallExecutionProcessor(200);

   /* Deassert INIT */

   APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT);

   if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) 
   {
      /* Clear APIC errors */
      APICWrite(APIC_ESR, 0);
      tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
   }

   Common = (PCOMMON_AREA_INFO)CommonBase;

   /* Write the location of the AP stack */
   Common->Stack = (ULONG)Stack;
   /* Write the page directory page */
   Common->PageDirectory = __readcr3();
   /* Write the kernel entry point */
   Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader((PVOID)KernelBase)->OptionalHeader.AddressOfEntryPoint + KernelBase;
   /* Write the state of the mae mode */
   Common->PaeModeEnabled = __readcr4() & CR4_PAE ? 1 : 0;

   DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled);

   DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack);
#if 0
   for (j = 0; j < 16; j++) 
   {
      Common->Debug[j] = 0;
   }
#endif

   maxlvt = APICGetMaxLVT();

   /* Is this a local APIC or an 82489DX? */
   StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0;

   for (i = 1; i <= StartupCount; i++)
   {
      /* It's a local APIC, so send STARTUP IPI */
      DPRINT("Sending startup signal %d\n", i);
      /* Clear errors */
      APICWrite(APIC_ESR, 0);
      APICRead(APIC_ESR);

      APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT);

      /* Wait up to 10ms for IPI to be delivered */
      j = 0;
      do 
      {
         KeStallExecutionProcessor(10);

         /* Check Delivery Status */
         DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;

         j++;
      } while ((DeliveryStatus) && (j < 1000));

      KeStallExecutionProcessor(200);

      /*
       * Due to the Pentium erratum 3AP.
       */
      if (maxlvt > 3) 
      {
        APICRead(APIC_SIVR);
        APICWrite(APIC_ESR, 0);
      }

      AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;

      if (DeliveryStatus || AcceptStatus) 
      {
         break;
      }
   }

   if (DeliveryStatus) 
   {
      DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu);
   }

   if (AcceptStatus) 
   {
      DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu);
   }

   if (!(DeliveryStatus || AcceptStatus)) 
   {

      /* Wait no more than 5 seconds for processor to boot */
      DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu);

      /* Wait no more than 5 seconds */
      for (j = 0; j < 50000; j++) 
      {
         if (CPUMap[Cpu].Flags & CPU_ENABLED)
	 {
            break;
	 }
         KeStallExecutionProcessor(100);
      }
   }

   if (CPUMap[Cpu].Flags & CPU_ENABLED) 
   {
      DbgPrint("CPU %d is now running\n", Cpu);
   } 
   else 
   {
      DbgPrint("Initialization of CPU %d failed\n", Cpu);
   }

#if 0
   DPRINT("Debug bytes are:\n");

   for (j = 0; j < 4; j++) 
   {
      DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
             Common->Debug[j*4+0],
             Common->Debug[j*4+1],
             Common->Debug[j*4+2],
             Common->Debug[j*4+3]);
   }

#endif
}

#endif

/* EOF */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -