Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions mythril_core/src/acpi/rsdp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ mod offsets {
pub const REVISION: usize = 15;
/// 32-bit physical address of the RSDT.
pub const RSDT_ADDR: Range<usize> = 16..20;
/// Length of the XSDT table in bytes (ACPI 2.0 only).
pub const LENGTH: Range<usize> = 20..24;
/// 64-bit physical address of the XSDT (ACPI 2.0 only).
pub const XSDT_ADDR: Range<usize> = 24..32;
/// Checksum of entire structure (ACPI 2.0 only).
Expand Down Expand Up @@ -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
},
}

Expand All @@ -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)
}
}
}
}
Expand Down Expand Up @@ -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]),
},
_ => {
Expand Down Expand Up @@ -202,8 +190,8 @@ impl RSDP {
/// Return the RSDT pointed to by this structure.
pub fn rsdt(&self) -> Result<RSDT> {
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),
}
}
}
110 changes: 82 additions & 28 deletions mythril_core/src/acpi/rsdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,27 +101,45 @@ 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<RSDT<'a>> {
/// Create a new RSDT.
pub fn new_rsdt(rsdt_addr: usize) -> Result<RSDT<'a>> {
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<RSDT<'a>> {
let sdt = unsafe { SDT::new(xsdt_addr as *const u8)? };
Ok(RSDT::XSDT(sdt))
}

/// Return the number of entries in the table.
///
/// 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.
Expand All @@ -137,41 +155,77 @@ 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 }
}
}

impl<'a> Iterator for RSDTIterator<'a> {
type Item = Result<SDT<'a>>;

fn next(&mut self) -> Option<Self::Item> {
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
}
}
}
}
}
33 changes: 22 additions & 11 deletions mythril_multiboot2/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,30 @@ impl VmServices for Multiboot2Services {
}

fn rsdp(&self) -> Result<acpi::rsdp::RSDP> {
// 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,
})
},
)
}
}
3 changes: 2 additions & 1 deletion scripts/grub.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}