From 7b2acdd79c22bbbb7319670fd8db187dcb90c00a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Aug 2016 12:16:32 -0600 Subject: [PATCH] Cleanup ACPI code, find lower tables --- Makefile | 5 ++- arch/x86_64/src/acpi/mod.rs | 70 +++++++++++++++++++++++++++++------- arch/x86_64/src/acpi/rsdt.rs | 41 +++++++++++++++++++++ arch/x86_64/src/acpi/sdt.rs | 24 +++++++++++-- arch/x86_64/src/acpi/xsdt.rs | 41 +++++++++++++++++++++ 5 files changed, 165 insertions(+), 16 deletions(-) create mode 100644 arch/x86_64/src/acpi/rsdt.rs create mode 100644 arch/x86_64/src/acpi/xsdt.rs diff --git a/Makefile b/Makefile index 6ab5a5c..993d224 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,10 @@ bochs: build/harddrive.bin bochs -f bochs.$(ARCH) qemu: build/harddrive.bin - qemu-system-$(ARCH) -serial mon:stdio -drive file=$<,format=raw,index=0,media=disk -nographic -d guest_errors + qemu-system-$(ARCH) -enable-kvm -cpu host -machine q35 \ + -serial mon:stdio -drive file=$<,format=raw,index=0,media=disk \ + -nographic -d guest_errors + #-device intel-iommu FORCE: diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs index 2e318fd..9614efe 100644 --- a/arch/x86_64/src/acpi/mod.rs +++ b/arch/x86_64/src/acpi/mod.rs @@ -1,14 +1,16 @@ //! # ACPI //! Code to parse the ACPI tables -use core::mem; - use memory::{Frame, FrameAllocator}; use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress}; -use self::sdt::SDTHeader; +use self::rsdt::RSDT; +use self::sdt::SDT; +use self::xsdt::XSDT; +pub mod rsdt; pub mod sdt; +pub mod xsdt; /// Parse the ACPI tables to gather CPU, interrupt, and timer information pub unsafe fn init(allocator: &mut A, active_table: &mut ActivePageTable) -> Option @@ -22,7 +24,9 @@ pub unsafe fn init(allocator: &mut A, active_table: &mut ActivePageTable) -> let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr)); let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr)); for frame in Frame::range_inclusive(start_frame, end_frame) { - active_table.identity_map(frame, entry::PRESENT | entry::NO_EXECUTE, allocator); + if active_table.translate_page(Page::containing_address(VirtualAddress::new(frame.start_address().get()))).is_none() { + active_table.identity_map(frame, entry::PRESENT | entry::NO_EXECUTE, allocator); + } } } @@ -30,15 +34,45 @@ pub unsafe fn init(allocator: &mut A, active_table: &mut ActivePageTable) -> if let Some(rsdp) = RSDP::search(start_addr, end_addr) { println!("{:?}", rsdp); - let rsdt_frame = Frame::containing_address(PhysicalAddress::new(rsdp.rsdt_address as usize)); - active_table.identity_map(rsdt_frame, entry::PRESENT | entry::NO_EXECUTE, allocator); + let mut get_sdt = |sdt_address: usize| -> &'static SDT { + if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() { + let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address)); + active_table.identity_map(sdt_frame, entry::PRESENT | entry::NO_EXECUTE, allocator); + } + unsafe { &*(sdt_address as *const SDT) } + }; - let sdt = unsafe { &*(rsdp.rsdt_address as usize as *const SDTHeader) }; - - for &c in sdt.signature.iter() { + let rxsdt = get_sdt(rsdp.sdt_address()); + + for &c in rxsdt.signature.iter() { print!("{}", c as char); } - println!(" {:?}", sdt); + println!(":"); + if let Some(rsdt) = RSDT::new(rxsdt) { + println!("{:?}", rsdt); + for sdt_address in rsdt.iter() { + let sdt = get_sdt(sdt_address); + for &c in sdt.signature.iter() { + print!("{}", c as char); + } + println!(":"); + println!("{:?}", sdt); + } + } else if let Some(xsdt) = XSDT::new(rxsdt) { + println!("{:?}", xsdt); + for sdt_address in xsdt.iter() { + let sdt = get_sdt(sdt_address); + for &c in sdt.signature.iter() { + print!("{}", c as char); + } + println!(":"); + println!("{:?}", sdt); + } + } else { + println!("UNKNOWN RSDT OR XSDT SIGNATURE"); + } + } else { + println!("NO RSDP FOUND"); } None @@ -56,19 +90,29 @@ pub struct RSDP { revision: u8, rsdt_address: u32, length: u32, - xsdt_address: u32, + xsdt_address: u64, extended_checksum: u8, reserved: [u8; 3] } impl RSDP { + /// Search for the RSDP pub fn search(start_addr: usize, end_addr: usize) -> Option { - for i in 0 .. (end_addr + 1 - start_addr)/mem::size_of::() { - let mut rsdp = unsafe { &*(start_addr as *const RSDP).offset(i as isize) }; + for i in 0 .. (end_addr + 1 - start_addr)/16 { + let mut rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) }; if &rsdp.signature == b"RSD PTR " { return Some(*rsdp); } } None } + + /// Get the RSDT or XSDT address + pub fn sdt_address(&self) -> usize { + if self.revision >= 2 { + self.xsdt_address as usize + } else { + self.rsdt_address as usize + } + } } diff --git a/arch/x86_64/src/acpi/rsdt.rs b/arch/x86_64/src/acpi/rsdt.rs new file mode 100644 index 0000000..3c2d018 --- /dev/null +++ b/arch/x86_64/src/acpi/rsdt.rs @@ -0,0 +1,41 @@ +use core::mem; + +use super::sdt::SDT; + +#[derive(Debug)] +pub struct RSDT(&'static SDT); + +impl RSDT { + pub fn new(sdt: &'static SDT) -> Option { + if &sdt.signature == b"RSDT" { + Some(RSDT(sdt)) + } else { + None + } + } + + pub fn iter(&self) -> RSDTIter { + RSDTIter { + sdt: self.0, + i: 0 + } + } +} + +pub struct RSDTIter { + sdt: &'static SDT, + i: usize +} + +impl Iterator for RSDTIter { + type Item = usize; + fn next(&mut self) -> Option { + if self.i < self.sdt.data_len()/mem::size_of::() { + let item = unsafe { *(self.sdt.data_address() as *const u32).offset(self.i as isize) }; + self.i += 1; + Some(item as usize) + } else { + None + } + } +} diff --git a/arch/x86_64/src/acpi/sdt.rs b/arch/x86_64/src/acpi/sdt.rs index f075d7f..15584f5 100644 --- a/arch/x86_64/src/acpi/sdt.rs +++ b/arch/x86_64/src/acpi/sdt.rs @@ -1,6 +1,8 @@ +use core::mem; + #[derive(Copy, Clone, Debug)] #[repr(packed)] -pub struct SDTHeader { +pub struct SDT { pub signature: [u8; 4], pub length: u32, pub revision: u8, @@ -9,5 +11,23 @@ pub struct SDTHeader { pub oem_table_id: [u8; 8], pub oem_revision: u32, pub creator_id: u32, - pub creator_revision: u32, + pub creator_revision: u32 +} + +impl SDT { + /// Get the address of this tables data + pub fn data_address(&'static self) -> usize { + self as *const _ as usize + mem::size_of::() + } + + /// Get the length of this tables data + pub fn data_len(&'static self) -> usize { + let total_size = self.length as usize; + let header_size = mem::size_of::(); + if total_size >= header_size { + total_size - header_size + } else { + 0 + } + } } diff --git a/arch/x86_64/src/acpi/xsdt.rs b/arch/x86_64/src/acpi/xsdt.rs new file mode 100644 index 0000000..3d2e9f2 --- /dev/null +++ b/arch/x86_64/src/acpi/xsdt.rs @@ -0,0 +1,41 @@ +use core::mem; + +use super::sdt::SDT; + +#[derive(Debug)] +pub struct XSDT(&'static SDT); + +impl XSDT { + pub fn new(sdt: &'static SDT) -> Option { + if &sdt.signature == b"XSDT" { + Some(XSDT(sdt)) + } else { + None + } + } + + pub fn iter(&self) -> XSDTIter { + XSDTIter { + sdt: self.0, + i: 0 + } + } +} + +pub struct XSDTIter { + sdt: &'static SDT, + i: usize +} + +impl Iterator for XSDTIter { + type Item = usize; + fn next(&mut self) -> Option { + if self.i < self.sdt.data_len()/mem::size_of::() { + let item = unsafe { *(self.sdt.data_address() as *const u64).offset(self.i as isize) }; + self.i += 1; + Some(item as usize) + } else { + None + } + } +}