|
|
|
@ -6,41 +6,44 @@
|
|
|
|
|
|
|
|
|
|
use core::ptr::{Unique};
|
|
|
|
|
use syscall::io::{Io, Mmio};
|
|
|
|
|
use bit_field::BitField;
|
|
|
|
|
use consts::irq::T_IRQ0;
|
|
|
|
|
|
|
|
|
|
pub unsafe fn init(ioapic_id: u8)
|
|
|
|
|
{
|
|
|
|
|
let ioapic = IOAPIC.as_mut();
|
|
|
|
|
let maxintr = (ioapic.read(REG_VER) >> 16) & 0xFF;
|
|
|
|
|
let id = (ioapic.read(REG_ID) >> 24) as u8;
|
|
|
|
|
assert!(id == ioapic_id, "ioapicinit: id isn't equal to ioapicid; not a MP");
|
|
|
|
|
assert!(ioapic.id() == ioapic_id, "ioapicinit: id isn't equal to ioapicid; not a MP");
|
|
|
|
|
|
|
|
|
|
// Mark all interrupts edge-triggered, active high, disabled,
|
|
|
|
|
// and not routed to any CPUs.
|
|
|
|
|
for i in 0 .. maxintr+1 {
|
|
|
|
|
ioapic.write(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
|
|
|
|
|
ioapic.write(REG_TABLE+2*i+1, 0);
|
|
|
|
|
for i in 0.. ioapic.maxintr() + 1 {
|
|
|
|
|
ioapic.write_irq(i, DISABLED, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC
|
|
|
|
|
|
|
|
|
|
const REG_ID : u32 = 0x00; // Register index: ID
|
|
|
|
|
const REG_VER : u32 = 0x01; // Register index: version
|
|
|
|
|
const REG_TABLE : u32 = 0x10; // Redirection table base
|
|
|
|
|
const REG_ID : u8 = 0x00; // Register index: ID
|
|
|
|
|
const REG_VER : u8 = 0x01; // Register index: version
|
|
|
|
|
const REG_TABLE : u8 = 0x10; // Redirection table base
|
|
|
|
|
|
|
|
|
|
// The redirection table starts at REG_TABLE and uses
|
|
|
|
|
// two registers to configure each interrupt.
|
|
|
|
|
// The first (low) register in a pair contains configuration bits.
|
|
|
|
|
// The second (high) register contains a bitmask telling which
|
|
|
|
|
// CPUs can serve that interrupt.
|
|
|
|
|
const INT_DISABLED : u32 = 0x00010000; // Interrupt disabled
|
|
|
|
|
const INT_LEVEL : u32 = 0x00008000; // Level-triggered (vs edge-)
|
|
|
|
|
const INT_ACTIVELOW : u32 = 0x00002000; // Active low (vs high)
|
|
|
|
|
const INT_LOGICAL : u32 = 0x00000800; // Destination is CPU id (vs APIC ID)
|
|
|
|
|
|
|
|
|
|
static mut IOAPIC: Unique<IoApic> = unsafe{ Unique::new_unchecked(IOAPIC_ADDRESS as *mut _) };
|
|
|
|
|
bitflags! {
|
|
|
|
|
flags RedirectionEntry: u32 {
|
|
|
|
|
const DISABLED = 0x00010000, // Interrupt disabled
|
|
|
|
|
const LEVEL = 0x00008000, // Level-triggered (vs edge-)
|
|
|
|
|
const ACTIVELOW = 0x00002000, // Active low (vs high)
|
|
|
|
|
const LOGICAL = 0x00000800, // Destination is CPU id (vs APIC ID)
|
|
|
|
|
const NONE = 0x00000000,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const T_IRQ0: u32 = 32;
|
|
|
|
|
static mut IOAPIC: Unique<IoApic> = unsafe{ Unique::new_unchecked(IOAPIC_ADDRESS as *mut _) };
|
|
|
|
|
|
|
|
|
|
// IO APIC MMIO structure: write reg, then read or write data.
|
|
|
|
|
#[repr(C)]
|
|
|
|
@ -51,22 +54,35 @@ struct IoApic {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl IoApic {
|
|
|
|
|
unsafe fn read(&mut self, reg: u32) -> u32
|
|
|
|
|
unsafe fn read(&mut self, reg: u8) -> u32
|
|
|
|
|
{
|
|
|
|
|
self.reg.write(reg);
|
|
|
|
|
self.reg.write(reg as u32);
|
|
|
|
|
self.data.read()
|
|
|
|
|
}
|
|
|
|
|
unsafe fn write(&mut self, reg: u32, data: u32)
|
|
|
|
|
unsafe fn write(&mut self, reg: u8, data: u32)
|
|
|
|
|
{
|
|
|
|
|
self.reg.write(reg);
|
|
|
|
|
self.reg.write(reg as u32);
|
|
|
|
|
self.data.write(data);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn enable(&mut self, irq: u32, cpunum: u32)
|
|
|
|
|
unsafe fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8)
|
|
|
|
|
{
|
|
|
|
|
self.write(REG_TABLE+2*irq, (T_IRQ0 + irq) as u32 | flags.bits());
|
|
|
|
|
self.write(REG_TABLE+2*irq+1, (dest as u32) << 24);
|
|
|
|
|
}
|
|
|
|
|
unsafe fn enable(&mut self, irq: u8, cpunum: u8)
|
|
|
|
|
{
|
|
|
|
|
// Mark interrupt edge-triggered, active high,
|
|
|
|
|
// enabled, and routed to the given cpunum,
|
|
|
|
|
// which happens to be that cpu's APIC ID.
|
|
|
|
|
self.write(REG_TABLE+2*irq, T_IRQ0 + irq);
|
|
|
|
|
self.write(REG_TABLE+2*irq+1, cpunum << 24);
|
|
|
|
|
self.write_irq(irq, NONE, cpunum);
|
|
|
|
|
}
|
|
|
|
|
fn id(&mut self) -> u8 {
|
|
|
|
|
unsafe{ self.read(REG_ID).get_bits(24..28) as u8 }
|
|
|
|
|
}
|
|
|
|
|
fn version(&mut self) -> u8 {
|
|
|
|
|
unsafe{ self.read(REG_VER).get_bits(0..8) as u8 }
|
|
|
|
|
}
|
|
|
|
|
fn maxintr(&mut self) -> u8 {
|
|
|
|
|
unsafe{ self.read(REG_VER).get_bits(16..24) as u8 }
|
|
|
|
|
}
|
|
|
|
|
}
|