diff --git a/src/lib.rs b/src/lib.rs index 3e7daa0b..9be69cf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub use elf_sections::{ElfSectionsTag, ElfSection, ElfSectionIter, ElfSectionTyp pub use memory_map::{MemoryMapTag, MemoryArea, MemoryAreaIter}; pub use module::{ModuleTag, ModuleIter}; pub use command_line::CommandLineTag; +pub use rsdp::{RsdpV1Tag, RsdpV2Tag}; #[macro_use] extern crate bitflags; @@ -20,6 +21,7 @@ mod elf_sections; mod memory_map; mod module; mod command_line; +mod rsdp; pub unsafe fn load(address: usize) -> BootInformation { if !cfg!(test) { @@ -74,6 +76,14 @@ impl BootInformation { self.get_tag(1).map(|tag| unsafe { &*(tag as *const Tag as *const CommandLineTag) }) } + pub fn rsdp_v1_tag(&self) -> Option<&'static RsdpV1Tag> { + self.get_tag(14).map(|tag| unsafe { &*(tag as *const Tag as *const RsdpV1Tag) }) + } + + pub fn rsdp_v2_tag(&self) -> Option<&'static RsdpV2Tag> { + self.get_tag(15).map(|tag| unsafe { &*(tag as *const Tag as *const RsdpV2Tag) }) + } + fn get(&self) -> &BootInformationInner { unsafe { &*self.inner } } @@ -568,6 +578,15 @@ mod tests { assert_eq!(0x7FE_0000, mm2.end_address()); assert_eq!(0x7EE_0000, mm2.size()); assert!(mm.next().is_none()); + + // Test the RSDP tag + let rsdp_old = bi.rsdp_v1_tag().unwrap(); + assert_eq!("RSD PTR ", rsdp_old.signature().unwrap()); + assert_eq!(89, rsdp_old.checksum()); + assert_eq!("BOCHS ", rsdp_old.oem_id().unwrap()); + assert_eq!(0, rsdp_old.revision()); + assert_eq!(0x7FE18DC, rsdp_old.rsdt_address()); + assert!(bi.module_tags().next().is_none()); assert_eq!("GRUB 2.02~beta3-5", bi.boot_loader_name_tag().unwrap().name()); assert_eq!("", bi.command_line_tag().unwrap().command_line()); diff --git a/src/rsdp.rs b/src/rsdp.rs new file mode 100644 index 00000000..ca45a953 --- /dev/null +++ b/src/rsdp.rs @@ -0,0 +1,85 @@ +/// The tag that the bootloader passes will depend on the ACPI version the hardware supports. +/// For ACPI Version 1.0, a `RsdpV1Tag` will be provided, which can be accessed from +/// `BootInformation` using the `rsdp_v1_tag` function. For subsequent versions of ACPI, a +/// `RsdpV2Tag` will be provided, which can be accessed with `rsdp_v2_tag`. +/// +/// Even though the bootloader should give the address of the real RSDP/XSDT, the checksum and +/// signature should be manually verified. + +use core::str; + +#[derive(Debug)] +#[repr(C, packed)] +pub struct RsdpV1Tag { + typ: u32, + size: u32, + signature: [u8; 8], + checksum: u8, + oem_id: [u8; 6], + revision: u8, + rsdt_address: u32, // This is the PHYSICAL address of the RSDT +} + +impl RsdpV1Tag { + pub fn signature<'a>(&'a self) -> Option<&'a str> { + str::from_utf8(&self.signature).ok() + } + + pub fn checksum(&self) -> u8 { + self.checksum + } + + pub fn oem_id<'a>(&'a self) -> Option<&'a str> { + str::from_utf8(&self.oem_id).ok() + } + + pub fn revision(&self) -> u8 { + self.revision + } + + pub fn rsdt_address(&self) -> usize { + self.rsdt_address as usize + } +} + +#[derive(Debug)] +#[repr(C, packed)] +pub struct RsdpV2Tag { + typ: u32, + size: u32, + signature: [u8; 8], + checksum: u8, + oem_id: [u8; 6], + revision: u8, + _rsdt_address: u32, + length: u32, + xsdt_address: u64, // This is the PHYSICAL address of the XSDT + ext_checksum: u8, + _reserved: [u8; 3], +} + +impl RsdpV2Tag { + pub fn signature<'a>(&'a self) -> Option<&'a str> { + str::from_utf8(&self.signature).ok() + } + + pub fn checksum(&self) -> u8 { + self.checksum + } + + pub fn oem_id<'a>(&'a self) -> Option<&'a str> { + str::from_utf8(&self.oem_id).ok() + } + + pub fn revision(&self) -> u8 { + self.revision + } + + pub fn xsdt_address(&self) -> usize { + self.xsdt_address as usize + } + + pub fn ext_checksum(&self) -> u8 { + self.ext_checksum + } +}