📄 ioapic.c
字号:
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: hal/halx86/generic/ioapic.c
* PURPOSE:
* PROGRAMMER:
*/
/* INCLUDES *****************************************************************/
#include <hal.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *****************************************************************/
MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */
ULONG IRQCount = 0; /* Number of IRQs */
ULONG IrqApicMap[MAX_IRQ_SOURCE];
UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */
UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */
IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */
ULONG IOAPICCount; /* Number of I/O APICs in the system */
ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */
/* EISA interrupts are always polarity zero and can be edge or level
* trigger depending on the ELCR value. If an interrupt is listed as
* EISA conforming in the MP table, that means its trigger type must
* be read in from the ELCR */
#define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq))
#define default_EISA_polarity(idx) (0)
/* ISA interrupts are always polarity zero edge triggered,
* when listed as conforming in the MP table. */
#define default_ISA_trigger(idx) (0)
#define default_ISA_polarity(idx) (0)
/* PCI interrupts are always polarity one level triggered,
* when listed as conforming in the MP table. */
#define default_PCI_trigger(idx) (1)
#define default_PCI_polarity(idx) (1)
/* MCA interrupts are always polarity zero level triggered,
* when listed as conforming in the MP table. */
#define default_MCA_trigger(idx) (1)
#define default_MCA_polarity(idx) (0)
/***************************************************************************/
extern VOID Disable8259AIrq(ULONG irq);
ULONG IOAPICRead(ULONG Apic, ULONG Offset);
VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value);
/* FUNCTIONS ***************************************************************/
/*
* EISA Edge/Level control register, ELCR
*/
static ULONG EISA_ELCR(ULONG irq)
{
if (irq < 16)
{
PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3));
return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1;
}
DPRINT("Broken MPtable reports ISA irq %d\n", irq);
return 0;
}
static ULONG
IRQPolarity(ULONG idx)
{
ULONG bus = IRQMap[idx].SrcBusId;
ULONG polarity;
/*
* Determine IRQ line polarity (high active or low active):
*/
switch (IRQMap[idx].IrqFlag & 3)
{
case 0: /* conforms, ie. bus-type dependent polarity */
{
switch (BUSMap[bus])
{
case MP_BUS_ISA: /* ISA pin */
polarity = default_ISA_polarity(idx);
break;
case MP_BUS_EISA: /* EISA pin */
polarity = default_EISA_polarity(idx);
break;
case MP_BUS_PCI: /* PCI pin */
polarity = default_PCI_polarity(idx);
break;
case MP_BUS_MCA: /* MCA pin */
polarity = default_MCA_polarity(idx);
break;
default:
DPRINT("Broken BIOS!!\n");
polarity = 1;
}
}
break;
case 1: /* high active */
polarity = 0;
break;
case 2: /* reserved */
DPRINT("Broken BIOS!!\n");
polarity = 1;
break;
case 3: /* low active */
polarity = 1;
break;
default: /* invalid */
DPRINT("Broken BIOS!!\n");
polarity = 1;
}
return polarity;
}
static ULONG
IRQTrigger(ULONG idx)
{
ULONG bus = IRQMap[idx].SrcBusId;
ULONG trigger;
/*
* Determine IRQ trigger mode (edge or level sensitive):
*/
switch ((IRQMap[idx].IrqFlag >> 2) & 3)
{
case 0: /* conforms, ie. bus-type dependent */
{
switch (BUSMap[bus])
{
case MP_BUS_ISA: /* ISA pin */
trigger = default_ISA_trigger(idx);
break;
case MP_BUS_EISA: /* EISA pin */
trigger = default_EISA_trigger(idx);
break;
case MP_BUS_PCI: /* PCI pin */
trigger = default_PCI_trigger(idx);
break;
case MP_BUS_MCA: /* MCA pin */
trigger = default_MCA_trigger(idx);
break;
default:
DPRINT("Broken BIOS!!\n");
trigger = 1;
}
}
break;
case 1: /* edge */
trigger = 0;
break;
case 2: /* reserved */
DPRINT("Broken BIOS!!\n");
trigger = 1;
break;
case 3: /* level */
trigger = 1;
break;
default: /* invalid */
DPRINT("Broken BIOS!!\n");
trigger = 0;
}
return trigger;
}
static ULONG
Pin2Irq(ULONG idx,
ULONG apic,
ULONG pin)
{
ULONG irq, i;
ULONG bus = IRQMap[idx].SrcBusId;
/*
* Debugging check, we are in big trouble if this message pops up!
*/
if (IRQMap[idx].DstApicInt != pin)
{
DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n");
}
switch (BUSMap[bus])
{
case MP_BUS_ISA: /* ISA pin */
case MP_BUS_EISA:
case MP_BUS_MCA:
irq = IRQMap[idx].SrcBusIrq;
break;
case MP_BUS_PCI: /* PCI pin */
/*
* PCI IRQs are mapped in order
*/
i = irq = 0;
while (i < apic)
{
irq += IOAPICMap[i++].EntryCount;
}
irq += pin;
break;
default:
DPRINT("Unknown bus type %d.\n",bus);
irq = 0;
}
return irq;
}
static ULONG
AssignIrqVector(ULONG irq)
{
#if 0
static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0;
#endif
ULONG vector;
/* There may already have been assigned a vector for this IRQ */
vector = IRQVectorMap[irq];
if (vector > 0)
{
return vector;
}
#if 0
if (current_vector > FIRST_SYSTEM_VECTOR)
{
vector_offset++;
current_vector = FIRST_DEVICE_VECTOR + vector_offset;
}
else if (current_vector == FIRST_SYSTEM_VECTOR)
{
DPRINT1("Ran out of interrupt sources!");
KEBUGCHECK(0);
}
vector = current_vector;
IRQVectorMap[irq] = vector;
current_vector += 8;
return vector;
#else
vector = IRQ2VECTOR(irq);
IRQVectorMap[irq] = vector;
return vector;
#endif
}
/*
* Find the IRQ entry number of a certain pin.
*/
static ULONG
IOAPICGetIrqEntry(ULONG apic,
ULONG pin,
ULONG type)
{
ULONG i;
for (i = 0; i < IRQCount; i++)
{
if (IRQMap[i].IrqType == type &&
(IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) &&
IRQMap[i].DstApicInt == pin)
{
return i;
}
}
return -1;
}
VOID
IOAPICSetupIrqs(VOID)
{
IOAPIC_ROUTE_ENTRY entry;
ULONG apic, pin, idx, irq, first_notcon = 1, vector, trigger;
DPRINT("Init IO_APIC IRQs\n");
/* Setup IRQ to vector translation map */
memset(&IRQVectorMap, 0, sizeof(IRQVectorMap));
for (apic = 0; apic < IOAPICCount; apic++)
{
for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++)
{
/*
* add it to the IO-APIC irq-routing table
*/
memset(&entry,0,sizeof(entry));
entry.delivery_mode = (APIC_DM_LOWEST >> 8);
entry.dest_mode = 1; /* logical delivery */
entry.mask = 1; /* disable IRQ */
entry.dest.logical.logical_dest = 0;
idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED);
if (idx == (ULONG)-1)
{
if (first_notcon)
{
DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin);
first_notcon = 0;
}
else
{
DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin);
}
continue;
}
trigger = IRQTrigger(idx);
entry.polarity = IRQPolarity(idx);
if (trigger)
{
entry.trigger = 1;
}
irq = Pin2Irq(idx, apic, pin);
vector = AssignIrqVector(irq);
entry.vector = vector;
DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq);
if (irq == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -