WIP: ACPI

Map and find ACPI tables, starting with RSDT
This commit is contained in:
Jeremy Soller 2016-08-15 18:37:58 -06:00
parent fda1ab2327
commit 7a1c263bc1
7 changed files with 133 additions and 33 deletions

View file

@ -0,0 +1,74 @@
//! # 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;
pub mod sdt;
/// 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>
where A: FrameAllocator
{
let start_addr = 0xE0000;
let end_addr = 0xFFFFF;
// Map all of the ACPI table space
{
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);
}
}
// Search for RSDP
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 sdt = unsafe { &*(rsdp.rsdt_address as usize as *const SDTHeader) };
for &c in sdt.signature.iter() {
print!("{}", c as char);
}
println!(" {:?}", sdt);
}
None
}
pub struct Acpi;
/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
signature: [u8; 8],
checksum: u8,
oemid: [u8; 6],
revision: u8,
rsdt_address: u32,
length: u32,
xsdt_address: u32,
extended_checksum: u8,
reserved: [u8; 3]
}
impl 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) };
if &rsdp.signature == b"RSD PTR " {
return Some(*rsdp);
}
}
None
}
}

View file

@ -0,0 +1,13 @@
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct SDTHeader {
pub signature: [u8; 4],
pub length: u32,
pub revision: u8,
pub checksum: u8,
pub oem_id: [u8; 6],
pub oem_table_id: [u8; 8],
pub oem_revision: u32,
pub creator_id: u32,
pub creator_revision: u32,
}

View file

@ -7,15 +7,28 @@ pub static mut IDTR: IdtDescriptor = IdtDescriptor {
pub static mut IDT: [IdtEntry; 256] = [IdtEntry::new(); 256];
pub unsafe fn init(func: unsafe extern fn()) {
for entry in IDT.iter_mut() {
pub unsafe fn init() {
for entry in IDT[0..32].iter_mut() {
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
entry.set_offset(8, func as usize);
entry.set_offset(8, exception as usize);
}
for entry in IDT[32..].iter_mut() {
entry.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
entry.set_offset(8, blank as usize);
}
IDTR.set_slice(&IDT);
IDTR.load();
}
interrupt!(blank, {
asm!("xchg bx, bx" : : : : "intel", "volatile");
println!("INTERRUPT");
});
interrupt!(exception, {
panic!("EXCEPTION");
});
bitflags! {
pub flags IdtFlags: u8 {
const IDT_PRESENT = 1 << 7,

View file

@ -76,6 +76,9 @@ macro_rules! interrupt {
};
}
/// ACPI table parsing
pub mod acpi;
/// Memcpy, memmove, etc.
pub mod externs;

View file

@ -5,14 +5,14 @@ use core::ops::{Deref, DerefMut};
use memory::{Frame, FrameAllocator};
use self::entry::{PRESENT, WRITABLE};
use self::entry::{EntryFlags, PRESENT, WRITABLE, NO_EXECUTE};
use self::mapper::Mapper;
use self::temporary_page::TemporaryPage;
pub mod entry;
mod mapper;
pub mod mapper;
pub mod table;
mod temporary_page;
pub mod temporary_page;
/// Number of entries per page table
pub const ENTRY_COUNT: usize = 512;
@ -43,8 +43,7 @@ pub unsafe fn init<A>(allocator: &mut A) -> ActivePageTable where A: FrameAlloca
let mut active_table = ActivePageTable::new();
let mut temporary_page = TemporaryPage::new(Page { number: 0x80000000 },
allocator);
let mut temporary_page = TemporaryPage::new(Page { number: 0x80000000 }, allocator);
let mut new_table = {
let frame = allocator.allocate_frame().expect("no more frames");
@ -52,7 +51,7 @@ pub unsafe fn init<A>(allocator: &mut A) -> ActivePageTable where A: FrameAlloca
};
active_table.with(&mut new_table, &mut temporary_page, |mapper| {
let mut remap = |start: usize, end: usize, flags: entry::EntryFlags| {
let mut remap = |start: usize, end: usize, flags: EntryFlags| {
/* TODO
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
let end_frame = Frame::containing_address(PhysicalAddress::new(end));
@ -65,20 +64,20 @@ pub unsafe fn init<A>(allocator: &mut A) -> ActivePageTable where A: FrameAlloca
};
// Remap stack writable, no execute
remap(0x00080000, 0x0009F000, entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE);
remap(0x00080000, 0x0009F000, PRESENT | WRITABLE | NO_EXECUTE);
// Remap a section with `flags`
let mut remap_section = |start: &u8, end: &u8, flags: entry::EntryFlags| {
let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| {
remap(start as *const _ as usize, end as *const _ as usize, flags);
};
// Remap text read-only
remap_section(& __text_start, & __text_end, entry::PRESENT);
remap_section(& __text_start, & __text_end, PRESENT);
// Remap rodata read-only, no execute
remap_section(& __rodata_start, & __rodata_end, entry::PRESENT | entry::NO_EXECUTE);
remap_section(& __rodata_start, & __rodata_end, PRESENT | NO_EXECUTE);
// Remap data writable, no execute
remap_section(& __data_start, & __data_end, entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE);
remap_section(& __data_start, & __data_end, PRESENT | NO_EXECUTE | WRITABLE);
// Remap bss writable, no execute
remap_section(& __bss_start, & __bss_end, entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE);
remap_section(& __bss_start, & __bss_end, PRESENT | NO_EXECUTE | WRITABLE);
});
active_table.switch(new_table);
@ -135,17 +134,17 @@ impl ActivePageTable {
let backup = Frame::containing_address(PhysicalAddress::new(unsafe { controlregs::cr3() } as usize));
// map temporary_page to current p4 table
let p4_table = temporary_page.map_table_frame(backup.clone(), self);
let p4_table = temporary_page.map_table_frame(backup.clone(), PRESENT | WRITABLE | NO_EXECUTE, self);
// overwrite recursive mapping
self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE | NO_EXECUTE);
flush_tlb();
// execute f in the new context
f(self);
// restore recursive mapping to original p4 table
p4_table[511].set(backup, PRESENT | WRITABLE);
p4_table[511].set(backup, PRESENT | WRITABLE | NO_EXECUTE);
flush_tlb();
}
@ -160,11 +159,11 @@ pub struct InactivePageTable {
impl InactivePageTable {
pub fn new(frame: Frame, active_table: &mut ActivePageTable, temporary_page: &mut TemporaryPage) -> InactivePageTable {
{
let table = temporary_page.map_table_frame(frame.clone(), active_table);
let table = temporary_page.map_table_frame(frame.clone(), PRESENT | WRITABLE | NO_EXECUTE, active_table);
// now we are able to zero the table
table.zero();
// set up recursive mapping for the table
table[511].set(frame.clone(), PRESENT | WRITABLE);
table[511].set(frame.clone(), PRESENT | WRITABLE | NO_EXECUTE);
}
temporary_page.unmap(active_table);
@ -207,7 +206,7 @@ pub struct Page {
}
impl Page {
fn start_address(&self) -> VirtualAddress {
pub fn start_address(&self) -> VirtualAddress {
VirtualAddress::new(self.number * PAGE_SIZE)
}

View file

@ -4,6 +4,7 @@
use memory::{Frame, FrameAllocator};
use super::{ActivePageTable, Page, VirtualAddress};
use super::entry::EntryFlags;
use super::table::{Table, Level1};
pub struct TemporaryPage {
@ -21,19 +22,17 @@ impl TemporaryPage {
/// Maps the temporary page to the given frame in the active table.
/// Returns the start address of the temporary page.
pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> VirtualAddress {
use super::entry::WRITABLE;
pub fn map(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> VirtualAddress {
assert!(active_table.translate_page(self.page).is_none(),
"temporary page is already mapped");
active_table.map_to(self.page, frame, WRITABLE, &mut self.allocator);
active_table.map_to(self.page, frame, flags, &mut self.allocator);
self.page.start_address()
}
/// Maps the temporary page to the given page table frame in the active
/// table. Returns a reference to the now mapped table.
pub fn map_table_frame(&mut self, frame: Frame, active_table: &mut ActivePageTable) -> &mut Table<Level1> {
unsafe { &mut *(self.map(frame, active_table).get() as *mut Table<Level1>) }
pub fn map_table_frame(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> &mut Table<Level1> {
unsafe { &mut *(self.map(frame, flags, active_table).get() as *mut Table<Level1>) }
}
/// Unmaps the temporary page in the active table.

View file

@ -3,6 +3,7 @@
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module
use acpi;
use allocator::{HEAP_START, HEAP_SIZE};
use externs::memset;
use gdt;
@ -48,7 +49,7 @@ pub unsafe extern fn kstart() -> ! {
gdt::init();
// Set up IDT
idt::init(blank);
idt::init();
// Initialize memory management
let mut allocator = memory::init(0, &__bss_end as *const u8 as usize);
@ -64,6 +65,9 @@ pub unsafe extern fn kstart() -> ! {
active_table.map(page, paging::entry::WRITABLE, &mut allocator);
}
// Read ACPI tables
acpi::init(&mut allocator, &mut active_table);
// Set global allocator
*::ALLOCATOR.lock() = Some(allocator);
@ -74,8 +78,3 @@ pub unsafe extern fn kstart() -> ! {
asm!("xchg bx, bx" : : : : "intel", "volatile");
kmain();
}
interrupt!(blank, {
asm!("xchg bx, bx" : : : : "intel", "volatile");
println!("INTERRUPT");
});