redox/kernel/arch/x86_64/src/acpi/madt.rs
2017-01-03 15:55:00 -07:00

134 lines
3.6 KiB
Rust

use core::mem;
use super::sdt::Sdt;
/// The Multiple APIC Descriptor Table
#[derive(Debug)]
pub struct Madt {
sdt: &'static Sdt,
pub local_address: u32,
pub flags: u32
}
impl Madt {
pub fn new(sdt: &'static Sdt) -> Option<Madt> {
if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags
let local_address = unsafe { *(sdt.data_address() as *const u32) };
let flags = unsafe { *(sdt.data_address() as *const u32).offset(1) };
Some(Madt {
sdt: sdt,
local_address: local_address,
flags: flags
})
} else {
None
}
}
pub fn iter(&self) -> MadtIter {
MadtIter {
sdt: self.sdt,
i: 8 // Skip local controller address and flags
}
}
}
///
/// MADT Local APIC
#[derive(Debug)]
#[repr(packed)]
pub struct MadtLocalApic {
/// Processor ID
pub processor: u8,
/// Local APIC ID
pub id: u8,
/// Flags. 1 means that the processor is enabled
pub flags: u32
}
/// MADT I/O APIC
#[derive(Debug)]
#[repr(packed)]
pub struct MadtIoApic {
/// I/O APIC ID
pub id: u8,
/// reserved
reserved: u8,
/// I/O APIC address
pub address: u32,
/// Global system interrupt base
pub gsi_base: u32
}
/// MADT Interrupt Source Override
#[derive(Debug)]
#[repr(packed)]
pub struct MadtIntSrcOverride {
/// Bus Source
pub bus_source: u8,
/// IRQ Source
pub irq_source: u8,
/// Global system interrupt base
pub gsi_base: u32,
/// Flags
pub flags: u16
}
/// MADT Entries
#[derive(Debug)]
pub enum MadtEntry {
LocalApic(&'static MadtLocalApic),
InvalidLocalApic(usize),
IoApic(&'static MadtIoApic),
InvalidIoApic(usize),
IntSrcOverride(&'static MadtIntSrcOverride),
InvalidIntSrcOverride(usize),
Unknown(u8)
}
pub struct MadtIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for MadtIter {
type Item = MadtEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.i + 1 < self.sdt.data_len() {
let entry_type = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize) };
let entry_len = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize + 1) } as usize;
if self.i + entry_len <= self.sdt.data_len() {
let item = match entry_type {
0 => if entry_len == mem::size_of::<MadtLocalApic>() + 2 {
MadtEntry::LocalApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApic) })
} else {
MadtEntry::InvalidLocalApic(entry_len)
},
1 => if entry_len == mem::size_of::<MadtIoApic>() + 2 {
MadtEntry::IoApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIoApic) })
} else {
MadtEntry::InvalidIoApic(entry_len)
},
2 => if entry_len == mem::size_of::<MadtIntSrcOverride>() + 2 {
MadtEntry::IntSrcOverride(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIntSrcOverride) })
} else {
MadtEntry::InvalidIntSrcOverride(entry_len)
},
_ => MadtEntry::Unknown(entry_type)
};
self.i += entry_len;
Some(item)
} else {
None
}
} else {
None
}
}
}