📄 apic.c
字号:
* 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 + -