1use bit_field::BitField;
9use bitflags::bitflags;
10
11bitflags! {
12 struct RedirectionEntry: u32 {
18 const DISABLED = 0x00010000;
20 const LEVEL = 0x00008000;
22 const ACTIVELOW = 0x00002000;
24 const LOGICAL = 0x00000800;
26 const NONE = 0x00000000;
28 }
29}
30
31pub struct IoApic {
32 reg: *mut u32,
33 data: *mut u32,
34}
35
36impl IoApic {
37 pub unsafe fn new(addr: usize) -> Self {
42 IoApic {
43 reg: addr as *mut u32,
44 data: (addr + 0x10) as *mut u32,
45 }
46 }
47 pub fn disable_all(&mut self) {
48 for i in 0..self.supported_interrupts() {
51 self.write_irq(i, RedirectionEntry::DISABLED, 0);
52 }
53 }
54
55 unsafe fn read(&mut self, reg: u8) -> u32 {
56 self.reg.write_volatile(reg as u32);
57 self.data.read_volatile()
58 }
59
60 unsafe fn write(&mut self, reg: u8, data: u32) {
61 self.reg.write_volatile(reg as u32);
62 self.data.write_volatile(data);
63 }
64
65 fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8) {
66 unsafe {
67 self.write(REG_TABLE + 2 * irq, (T_IRQ0 + irq) as u32 | flags.bits());
68 self.write(REG_TABLE + 2 * irq + 1, (dest as u32) << 24);
69 }
70 }
71
72 pub fn enable(&mut self, irq: u8, cpunum: u8) {
73 self.write_irq(irq, RedirectionEntry::NONE, cpunum);
77 }
78
79 pub fn id(&mut self) -> u8 {
80 unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
81 }
82
83 pub fn version(&mut self) -> u8 {
84 unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
85 }
86
87 pub fn supported_interrupts(&mut self) -> u8 {
92 unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
93 }
94}
95
96const REG_ID: u8 = 0x00;
98
99const REG_VER: u8 = 0x01;
101
102const REG_TABLE: u8 = 0x10;
104
105const T_IRQ0: u8 = 32;