📄 ioapic.c
字号:
{
/* Mask timer IRQ */
entry.mask = 1;
}
if ((apic == 0) && (irq < 16))
{
Disable8259AIrq(irq);
}
IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1));
IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0));
IrqApicMap[irq] = apic;
DPRINT("Vector %x, Pin %x, Irq %x\n", vector, pin, irq);
}
}
}
static VOID
IOAPICClearPin(ULONG Apic, ULONG Pin)
{
IOAPIC_ROUTE_ENTRY Entry;
DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic, Pin);
/*
* Disable it in the IO-APIC irq-routing table
*/
memset(&Entry, 0, sizeof(Entry));
Entry.mask = 1;
IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0));
IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1));
}
static VOID
IOAPICClear(ULONG Apic)
{
ULONG Pin;
for (Pin = 0; Pin < /*IOAPICMap[Apic].EntryCount*/24; Pin++)
{
IOAPICClearPin(Apic, Pin);
}
}
static VOID
IOAPICClearAll(VOID)
{
ULONG Apic;
for (Apic = 0; Apic < IOAPICCount; Apic++)
{
IOAPICClear(Apic);
}
}
VOID
IOAPICEnable(VOID)
{
ULONG i, tmp;
/* Setup IRQ to vector translation map */
memset(&IRQVectorMap, 0, sizeof(IRQVectorMap));
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
for (i = 0; i < IOAPICCount; i++)
{
tmp = IOAPICRead(i, IOAPIC_VER);
IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1;
}
/*
* Do not trust the IO-APIC being empty at bootup
*/
IOAPICClearAll();
}
VOID
IOAPICSetupIds(VOID)
{
ULONG tmp, apic, i;
UCHAR old_id;
/*
* Set the IOAPIC ID to the value stored in the MPC table.
*/
for (apic = 0; apic < IOAPICCount; apic++)
{
/* Read the register 0 value */
tmp = IOAPICRead(apic, IOAPIC_ID);
old_id = IOAPICMap[apic].ApicId;
if (IOAPICMap[apic].ApicId >= 0xf)
{
DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
apic, IOAPICMap[apic].ApicId);
DPRINT1("... fixing up to %d. (tell your hw vendor)\n",
GET_IOAPIC_ID(tmp));
IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp);
}
/*
* We need to adjust the IRQ routing table
* if the ID changed.
*/
if (old_id != IOAPICMap[apic].ApicId)
{
for (i = 0; i < IRQCount; i++)
{
if (IRQMap[i].DstApicId == old_id)
{
IRQMap[i].DstApicId = IOAPICMap[apic].ApicId;
}
}
}
/*
* Read the right value from the MPC table and
* write it into the ID register.
*/
DPRINT("Changing IO-APIC physical APIC ID to %d\n",
IOAPICMap[apic].ApicId);
tmp &= ~IOAPIC_ID_MASK;
tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId);
IOAPICWrite(apic, IOAPIC_ID, tmp);
/*
* Sanity check
*/
tmp = IOAPICRead(apic, 0);
if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId)
{
DPRINT1("Could not set I/O APIC ID!\n");
KEBUGCHECK(0);
}
}
}
/* This is performance critical and should probably be done in assembler */
VOID IOAPICMaskIrq(ULONG Irq)
{
IOAPIC_ROUTE_ENTRY Entry;
ULONG Apic = IrqApicMap[Irq];
*(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
*(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1);
Entry.dest.logical.logical_dest &= ~(1 << KeGetCurrentProcessorNumber());
if (Entry.dest.logical.logical_dest == 0)
{
Entry.mask = 1;
}
IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1));
IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0));
}
/* This is performance critical and should probably be done in assembler */
VOID IOAPICUnmaskIrq(ULONG Irq)
{
IOAPIC_ROUTE_ENTRY Entry;
ULONG Apic = IrqApicMap[Irq];
*(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq);
*(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1);
Entry.dest.logical.logical_dest |= 1 << KeGetCurrentProcessorNumber();
Entry.mask = 0;
IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1));
IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0));
}
VOID IOAPICDump(VOID)
{
ULONG apic, i;
ULONG reg0, reg1, reg2=0;
DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount);
for (i = 0; i < IOAPICCount; i++)
{
DbgPrint("Number of IO-APIC #%d registers: %d.\n",
IOAPICMap[i].ApicId,
IOAPICMap[i].EntryCount);
}
/*
* We are a bit conservative about what we expect. We have to
* know about every hardware change ASAP.
*/
DbgPrint("Testing the IO APIC.......................\n");
for (apic = 0; apic < IOAPICCount; apic++)
{
reg0 = IOAPICRead(apic, IOAPIC_ID);
reg1 = IOAPICRead(apic, IOAPIC_VER);
if (GET_IOAPIC_VERSION(reg1) >= 0x10)
{
reg2 = IOAPICRead(apic, IOAPIC_ARB);
}
DbgPrint("\n");
DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId);
DbgPrint(".... register #00: %08X\n", reg0);
DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0));
if (reg0 & 0xF0FFFFFF)
{
DbgPrint(" WARNING: Unexpected IO-APIC\n");
}
DbgPrint(".... register #01: %08X\n", reg1);
i = GET_IOAPIC_MRE(reg1);
DbgPrint("....... : max redirection entries: %04X\n", i);
if ((i != 0x0f) && /* older (Neptune) boards */
(i != 0x17) && /* typical ISA+PCI boards */
(i != 0x1b) && /* Compaq Proliant boards */
(i != 0x1f) && /* dual Xeon boards */
(i != 0x22) && /* bigger Xeon boards */
(i != 0x2E) &&
(i != 0x3F))
{
DbgPrint(" WARNING: Unexpected IO-APIC\n");
}
i = GET_IOAPIC_VERSION(reg1);
DbgPrint("....... : IO APIC version: %04X\n", i);
if ((i != 0x01) && /* 82489DX IO-APICs */
(i != 0x10) && /* oldest IO-APICs */
(i != 0x11) && /* Pentium/Pro IO-APICs */
(i != 0x13)) /* Xeon IO-APICs */
{
DbgPrint(" WARNING: Unexpected IO-APIC\n");
}
if (reg1 & 0xFF00FF00)
{
DbgPrint(" WARNING: Unexpected IO-APIC\n");
}
if (GET_IOAPIC_VERSION(reg1) >= 0x10)
{
DbgPrint(".... register #02: %08X\n", reg2);
DbgPrint("....... : arbitration: %02X\n",
GET_IOAPIC_ARB(reg2));
if (reg2 & 0xF0FFFFFF)
{
DbgPrint(" WARNING: Unexpected IO-APIC\n");
}
}
DbgPrint(".... IRQ redirection table:\n");
DbgPrint(" NR Log Phy Mask Trig IRR Pol"
" Stat Dest Deli Vect: \n");
for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++)
{
IOAPIC_ROUTE_ENTRY entry;
*(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2);
*(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2);
DbgPrint(" %02x %03X %02X ",
i,
entry.dest.logical.logical_dest,
entry.dest.physical.physical_dest);
DbgPrint("%C %C %1d %C %C %C %03X %02X\n",
(entry.mask == 0) ? 'U' : 'M', // Unmasked/masked
(entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive
entry.irr,
(entry.polarity == 0) ? 'H' : 'L', // Active high/active low
(entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending
(entry.dest_mode == 0) ? 'P' : 'L', // Physical logical
entry.delivery_mode,
entry.vector);
}
}
DbgPrint(".................................... done.\n");
}
VOID
HaliReconfigurePciInterrupts(VOID)
{
ULONG i;
for (i = 0; i < IRQCount; i++)
{
if (BUSMap[IRQMap[i].SrcBusId] == MP_BUS_PCI)
{
DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x"
", DstApicId %02x, DstApicInt %02x\n",
i, IRQMap[i].IrqType, IRQMap[i].IrqFlag, IRQMap[i].SrcBusId,
IRQMap[i].SrcBusIrq, IRQMap[i].DstApicId, IRQMap[i].DstApicInt);
if(1 != HalSetBusDataByOffset(PCIConfiguration,
IRQMap[i].SrcBusId,
(IRQMap[i].SrcBusIrq >> 2) & 0x1f,
&IRQMap[i].DstApicInt,
0x3c /*PCI_INTERRUPT_LINE*/,
1))
{
CHECKPOINT;
}
}
}
}
VOID Disable8259AIrq(ULONG irq)
{
ULONG tmp;
if (irq >= 8)
{
tmp = READ_PORT_UCHAR((PUCHAR)0xA1);
tmp |= (1 << (irq - 8));
WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp);
}
else
{
tmp = READ_PORT_UCHAR((PUCHAR)0x21);
tmp |= (1 << irq);
WRITE_PORT_UCHAR((PUCHAR)0x21, tmp);
}
}
ULONG IOAPICRead(ULONG Apic, ULONG Offset)
{
PULONG Base;
Base = (PULONG)IOAPICMap[Apic].ApicAddress;
*Base = Offset;
return *((PULONG)((ULONG)Base + IOAPIC_IOWIN));
}
VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value)
{
PULONG Base;
Base = (PULONG)IOAPICMap[Apic].ApicAddress;
*Base = Offset;
*((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -