WIP: ACPI
Map and find ACPI tables, starting with RSDT
This commit is contained in:
parent
fda1ab2327
commit
7a1c263bc1
74
arch/x86_64/src/acpi/mod.rs
Normal file
74
arch/x86_64/src/acpi/mod.rs
Normal 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
|
||||
}
|
||||
}
|
13
arch/x86_64/src/acpi/sdt.rs
Normal file
13
arch/x86_64/src/acpi/sdt.rs
Normal 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,
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -76,6 +76,9 @@ macro_rules! interrupt {
|
|||
};
|
||||
}
|
||||
|
||||
/// ACPI table parsing
|
||||
pub mod acpi;
|
||||
|
||||
/// Memcpy, memmove, etc.
|
||||
pub mod externs;
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue