Cleanup ACPI code, find lower tables

This commit is contained in:
Jeremy Soller 2016-08-16 12:16:32 -06:00
parent d383cfb595
commit 7b2acdd79c
5 changed files with 165 additions and 16 deletions

View file

@ -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:

View file

@ -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<A>(allocator: &mut A, active_table: &mut ActivePageTable) -> Option<Acpi>
@ -22,7 +24,9 @@ pub unsafe fn init<A>(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<A>(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<RSDP> {
for i in 0 .. (end_addr + 1 - start_addr)/mem::size_of::<RSDP>() {
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
}
}
}

View file

@ -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<RSDT> {
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<Self::Item> {
if self.i < self.sdt.data_len()/mem::size_of::<u32>() {
let item = unsafe { *(self.sdt.data_address() as *const u32).offset(self.i as isize) };
self.i += 1;
Some(item as usize)
} else {
None
}
}
}

View file

@ -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::<SDT>()
}
/// 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::<SDT>();
if total_size >= header_size {
total_size - header_size
} else {
0
}
}
}

View file

@ -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<XSDT> {
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<Self::Item> {
if self.i < self.sdt.data_len()/mem::size_of::<u64>() {
let item = unsafe { *(self.sdt.data_address() as *const u64).offset(self.i as isize) };
self.i += 1;
Some(item as usize)
} else {
None
}
}
}