diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs new file mode 100644 index 0000000..2e318fd --- /dev/null +++ b/arch/x86_64/src/acpi/mod.rs @@ -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(allocator: &mut A, active_table: &mut ActivePageTable) -> Option + 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 { + 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) }; + if &rsdp.signature == b"RSD PTR " { + return Some(*rsdp); + } + } + None + } +} diff --git a/arch/x86_64/src/acpi/sdt.rs b/arch/x86_64/src/acpi/sdt.rs new file mode 100644 index 0000000..f075d7f --- /dev/null +++ b/arch/x86_64/src/acpi/sdt.rs @@ -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, +} diff --git a/arch/x86_64/src/idt.rs b/arch/x86_64/src/idt.rs index 0b08cd2..318242e 100644 --- a/arch/x86_64/src/idt.rs +++ b/arch/x86_64/src/idt.rs @@ -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, diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index eabc8a8..96f4142 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -76,6 +76,9 @@ macro_rules! interrupt { }; } +/// ACPI table parsing +pub mod acpi; + /// Memcpy, memmove, etc. pub mod externs; diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 4caa25d..1de6233 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -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(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(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(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) } diff --git a/arch/x86_64/src/paging/temporary_page.rs b/arch/x86_64/src/paging/temporary_page.rs index 24e1ed7..13ad2c2 100644 --- a/arch/x86_64/src/paging/temporary_page.rs +++ b/arch/x86_64/src/paging/temporary_page.rs @@ -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 { - unsafe { &mut *(self.map(frame, active_table).get() as *mut Table) } + pub fn map_table_frame(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> &mut Table { + unsafe { &mut *(self.map(frame, flags, active_table).get() as *mut Table) } } /// Unmaps the temporary page in the active table. diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index c70d2bd..d9221dd 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -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"); -});