diff --git a/src/arch/x86_64/driver/apic/ioapic.rs b/src/arch/x86_64/driver/apic/ioapic.rs index b68f197..64da4eb 100644 --- a/src/arch/x86_64/driver/apic/ioapic.rs +++ b/src/arch/x86_64/driver/apic/ioapic.rs @@ -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 = 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 = 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 } } } \ No newline at end of file diff --git a/src/consts.rs b/src/consts.rs index 9e82028..b3e245f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1 +1,11 @@ -pub const MAX_CPU_NUM: usize = 8; \ No newline at end of file +pub const MAX_CPU_NUM: usize = 8; + +pub mod irq { + pub const T_IRQ0 : u8 = 32; // IRQ 0 corresponds to int T_IRQ + pub const IRQ_TIMER : u8 = 0; + pub const IRQ_KBD : u8 = 1; + pub const IRQ_COM1 : u8 = 4; + pub const IRQ_IDE : u8 = 14; + pub const IRQ_ERROR : u8 = 19; + pub const IRQ_SPURIOUS : u8 = 31; +}