diff --git a/mythril_core/src/acpi/rsdp.rs b/mythril_core/src/acpi/rsdp.rs index cfb82c5..6e73e0f 100644 --- a/mythril_core/src/acpi/rsdp.rs +++ b/mythril_core/src/acpi/rsdp.rs @@ -30,8 +30,6 @@ mod offsets { pub const REVISION: usize = 15; /// 32-bit physical address of the RSDT. pub const RSDT_ADDR: Range = 16..20; - /// Length of the XSDT table in bytes (ACPI 2.0 only). - pub const LENGTH: Range = 20..24; /// 64-bit physical address of the XSDT (ACPI 2.0 only). pub const XSDT_ADDR: Range = 24..32; /// Checksum of entire structure (ACPI 2.0 only). @@ -60,12 +58,10 @@ pub enum RSDP { V2 { /// OEM Supplied string. oemid: [u8; 6], - /// 32-bit physical address of the RSDT. - rsdt_addr: u32, - /// Length of the XSDT table in bytes. - length: u32, /// 64-bit physical address of the XSDT. xsdt_addr: u64, + // TODO(ntegan) multiboot2 doesn't give us a length for rsdpv2tag, + // so we can't calculate the rsdp checksum }, } @@ -75,15 +71,9 @@ impl fmt::Debug for RSDP { &RSDP::V1 { rsdt_addr, .. } => { write!(f, "RSDP: revision=1.0 rsdt=0x{:x}", rsdt_addr) } - &RSDP::V2 { - rsdt_addr, - xsdt_addr, - .. - } => write!( - f, - "RSDP: revision=2.0 rsdt=0x{:x} xsdt_addr=0x{:x}", - rsdt_addr, xsdt_addr - ), + &RSDP::V2 { xsdt_addr, .. } => { + write!(f, "RSDP: revision=2.0 xsdt_addr=0x{:x}", xsdt_addr) + } } } } @@ -125,8 +115,6 @@ impl RSDP { // This is ACPI 2.0. Extract the addrss and length of the XSDT. 2 => RSDP::V2 { oemid, - rsdt_addr, - length: NativeEndian::read_u32(&bytes[offsets::LENGTH]), xsdt_addr: NativeEndian::read_u64(&bytes[offsets::XSDT_ADDR]), }, _ => { @@ -202,8 +190,8 @@ impl RSDP { /// Return the RSDT pointed to by this structure. pub fn rsdt(&self) -> Result { match self { - &RSDP::V1 { rsdt_addr, .. } => RSDT::new(rsdt_addr), - &RSDP::V2 { .. } => Err(Error::NotSupported), + &RSDP::V1 { rsdt_addr, .. } => RSDT::new_rsdt(rsdt_addr as usize), + &RSDP::V2 { xsdt_addr, .. } => RSDT::new_xsdt(xsdt_addr as usize), } } } diff --git a/mythril_core/src/acpi/rsdt.rs b/mythril_core/src/acpi/rsdt.rs index 26eeb36..0efdbbf 100644 --- a/mythril_core/src/acpi/rsdt.rs +++ b/mythril_core/src/acpi/rsdt.rs @@ -101,14 +101,26 @@ impl<'a> SDT<'a> { } } -/// The Root System Descriptor Table. -pub struct RSDT<'a>(SDT<'a>); +/// The Root System Description Table. +/// Two variants to support 32 bit RSDT and 64 bit XSDT. +pub enum RSDT<'a> { + /// Root System Description Table. + RSDT(SDT<'a>), + /// Extended System Description Table. + XSDT(SDT<'a>), +} impl<'a> RSDT<'a> { - /// Create a new SDT. - pub fn new(rsdt_addr: u32) -> Result> { + /// Create a new RSDT. + pub fn new_rsdt(rsdt_addr: usize) -> Result> { let sdt = unsafe { SDT::new(rsdt_addr as *const u8)? }; - Ok(RSDT(sdt)) + Ok(RSDT::RSDT(sdt)) + } + + /// Create a new XSDT. + pub fn new_xsdt(xsdt_addr: usize) -> Result> { + let sdt = unsafe { SDT::new(xsdt_addr as *const u8)? }; + Ok(RSDT::XSDT(sdt)) } /// Return the number of entries in the table. @@ -116,12 +128,18 @@ impl<'a> RSDT<'a> { /// Note: This is not the same as the length value of the header. /// the the length value _includes_ the header. pub fn num_entries(&self) -> usize { - self.0.len() / 4 + match self { + RSDT::XSDT(sdt) => sdt.len() / 8, + RSDT::RSDT(sdt) => sdt.len() / 4, + } } /// Return an iterator for the SDT entries. pub fn entries(&self) -> RSDTIterator<'a> { - RSDTIterator::new(self.0.table) + match self { + RSDT::RSDT(sdt) => RSDTIterator::new_rsdt(sdt.table), + RSDT::XSDT(sdt) => RSDTIterator::new_xsdt(sdt.table), + } } /// Returns the first matching SDT for a given signature. @@ -137,20 +155,41 @@ impl<'a> RSDT<'a> { impl<'a> fmt::Debug for RSDT<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.0) + let my_sdt = match self { + RSDT::RSDT(the_sdt) => the_sdt, + RSDT::XSDT(the_sdt) => the_sdt, + }; + write!(f, "{:?}", my_sdt) } } -/// Iterator for the SDT entries found in the RSDT. -pub struct RSDTIterator<'a> { - table: &'a [u8], - offset: usize, +/// Iterator for the SDT entries found in the RSDT/XSDT. +pub enum RSDTIterator<'a> { + /// Iterates through 32 bit RSDT. + RSDTIterator { + /// Table of 32 bit SDT pointers. + table: &'a [u8], + /// Current offset to keep track of iteration. + offset: usize, + }, + /// Iterates through 64 bit XSDT. + XSDTIterator { + /// Table of 64 bit SDT pointers. + table: &'a [u8], + /// Current offset to keep track of iteration. + offset: usize, + }, } impl<'a> RSDTIterator<'a> { /// Create an iterator for the SDT entries in an RSDT. - pub fn new<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> { - RSDTIterator { table, offset: 0 } + pub fn new_rsdt<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> { + RSDTIterator::RSDTIterator { table, offset: 0 } + } + + /// Create an iterator for the SDT entries in an XSDT. + pub fn new_xsdt<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> { + RSDTIterator::XSDTIterator { table, offset: 0 } } } @@ -158,20 +197,35 @@ impl<'a> Iterator for RSDTIterator<'a> { type Item = Result>; fn next(&mut self) -> Option { - let next = self.offset + 4; - if next <= self.table.len() { - let item = unsafe { - // TODO(dlrobertson): We currently only support the 32-bit RSDT. - // When we support the 64-bit XSDT, the table may point to an - // array of 64-bit pointers. - let ptr = - NativeEndian::read_u32(&self.table[self.offset..next]); - self.offset = next; - SDT::new(ptr as *const u8) - }; - Some(item) - } else { - None + match self { + RSDTIterator::RSDTIterator { table, offset } => { + let next = *offset + 4usize; + if next <= table.len() { + let item = unsafe { + let ptr = NativeEndian::read_u32(&table[*offset..next]) + as usize; + *offset = next; + SDT::new(ptr as *const u8) + }; + Some(item) + } else { + None + } + } + RSDTIterator::XSDTIterator { table, offset } => { + let next = *offset + 8usize; + if next <= table.len() { + let item = unsafe { + let ptr = NativeEndian::read_u64(&table[*offset..next]) + as usize; + *offset = next; + SDT::new(ptr as *const u8) + }; + Some(item) + } else { + None + } + } } } } diff --git a/mythril_multiboot2/src/services.rs b/mythril_multiboot2/src/services.rs index 6aeddcf..afbaaa3 100644 --- a/mythril_multiboot2/src/services.rs +++ b/mythril_multiboot2/src/services.rs @@ -35,19 +35,30 @@ impl VmServices for Multiboot2Services { } fn rsdp(&self) -> Result { - // Get a v1 tag if possible - self.info - .rsdp_v1_tag() - .map(|tag| { - // use empty string if no OEM id provided - let id = tag.oem_id().unwrap_or(" ").as_bytes(); + let mut arr: [u8; 6] = [0; 6]; + self.info.rsdp_v2_tag().map_or_else( + || { + self.info.rsdp_v1_tag().map_or_else( + || Err(Error::NotFound), + move |tag_v1| { + let id = tag_v1.oem_id().unwrap_or(" ").as_bytes(); + arr.copy_from_slice(&id[0..6]); + Ok(acpi::rsdp::RSDP::V1 { + oemid: arr, + rsdt_addr: tag_v1.rsdt_address() as u32, + }) + }, + ) + }, + move |tag_v2| { + let id = tag_v2.oem_id().unwrap_or(" ").as_bytes(); let mut arr: [u8; 6] = [0; 6]; arr.copy_from_slice(&id[0..6]); - acpi::rsdp::RSDP::V1 { + Ok(acpi::rsdp::RSDP::V2 { oemid: arr, - rsdt_addr: tag.rsdt_address() as u32, - } - }) - .ok_or(Error::NotFound) + xsdt_addr: tag_v2.xsdt_address() as u64, + }) + }, + ) } } diff --git a/scripts/grub.cfg b/scripts/grub.cfg index d6cf39c..64293c6 100644 --- a/scripts/grub.cfg +++ b/scripts/grub.cfg @@ -3,9 +3,10 @@ set timeout=0 menuentry 'Mythril' { echo 'Loading Mythril' + acpi -2 multiboot2 /boot/mythril.bin module2 /boot/seabios.bin seabios.bin module2 /boot/linuxboot_dma.bin linuxboot_dma.bin module2 /boot/vmlinuz kernel module2 /boot/initramfs initramfs -} \ No newline at end of file +}