133 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			133 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
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |