diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs index 23a7b97..d0b0b8c 100644 --- a/src/interrupts/mod.rs +++ b/src/interrupts/mod.rs @@ -1,5 +1,5 @@ use x86_64::VirtualAddress; -use arch::idt::{Idt, ExceptionStackFrame}; +use arch::idt::{Idt, ExceptionStackFrame, PageFaultErrorCode}; use x86_64::structures::tss::TaskStateSegment; use memory::{MemoryController, as_ref_in_real}; use spin::Once; @@ -16,6 +16,7 @@ const DOUBLE_FAULT_IST_INDEX: usize = 0; pub unsafe fn init_idt() { IDT.breakpoint.set_handler_fn(*as_ref_in_real(&breakpoint_handler)); IDT.double_fault.set_handler_fn(*as_ref_in_real(&double_fault_handler)); + IDT.page_fault.set_handler_fn(*as_ref_in_real(&page_fault_handler)); // .set_stack_index(DOUBLE_FAULT_IST_INDEX as u16); IDT.load(); } @@ -67,3 +68,12 @@ extern "x86-interrupt" fn double_fault_handler( println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); loop {} } + +extern "x86-interrupt" fn page_fault_handler( + stack_frame: &mut ExceptionStackFrame, _error_code: PageFaultErrorCode) +{ + use x86_64::registers::control_regs::cr2; + let addr = cr2(); + println!("\nEXCEPTION: PAGE FAULT\n{:#?}\nAddress: {:#x}", stack_frame, addr); + loop {} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b30f33a..00c0c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,10 +49,10 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page println!("Hello World{}", "!"); unsafe{ interrupts::init_idt(); } - unsafe{ let a = *(0xdeadbeaf as *const u8); } // double fault + // unsafe{ let a = *(0xdeadbeaf as *const u8); } // page fault let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; - arch::init(); + arch::init(); // set up guard page and map the heap pages let mut memory_controller = memory::init(boot_info); diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 6c58db0..97968b4 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,5 +1,5 @@ pub use self::area_frame_allocator::AreaFrameAllocator; -pub use self::paging::remap_the_kernel; +pub use self::paging::*; pub use self::stack_allocator::Stack; pub use self::address::*; @@ -46,8 +46,7 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { boot_info_start, boot_info_end, memory_map_tag.memory_areas()); - let mut active_table = paging::remap_the_kernel(&mut frame_allocator, - boot_info); + let mut active_table = remap_the_kernel(&mut frame_allocator, boot_info); println!("{:?}", active_table); @@ -76,6 +75,76 @@ pub fn init(boot_info: &BootInformation) -> MemoryController { } } +pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) + -> ActivePageTable + where A: FrameAllocator +{ + let mut temporary_page = TemporaryPage::new(Page::containing_address(0xcafebabe), allocator); + + let mut active_table = unsafe { ActivePageTable::new() }; + let mut new_table = { + let frame = allocator.allocate_frame().expect("no more frames"); + InactivePageTable::new(frame, &mut active_table, &mut temporary_page) + }; + + active_table.with(&mut new_table, &mut temporary_page, |mapper| { + let elf_sections_tag = boot_info.elf_sections_tag() + .expect("Memory map tag required"); + + for section in elf_sections_tag.sections() { + if !section.is_allocated() { + // section is not loaded to memory + continue; + } + assert!(section.start_address() % PAGE_SIZE == 0, + "sections need to be page aligned"); + + println!("mapping section at addr: {:#x}, size: {:#x}", + section.addr, section.size); + + let flags = EntryFlags::from_elf_section_flags(section); + + fn to_physical_frame(addr: usize) -> Frame { + Frame::containing_address( + if addr < KERNEL_OFFSET { addr } + else { addr - KERNEL_OFFSET }) + } + + let start_frame = to_physical_frame(section.start_address()); + let end_frame = to_physical_frame(section.end_address() - 1); + + for frame in Frame::range_inclusive(start_frame, end_frame) { + let page = Page::containing_address(frame.start_address().to_kernel_virtual()); + mapper.map_to(page, frame, flags, allocator); + } + } + + // identity map the VGA text buffer + let vga_buffer_frame = Frame::containing_address(0xb8000); + mapper.identity_map(vga_buffer_frame, WRITABLE, allocator); + + // identity map the multiboot info structure + let multiboot_start = Frame::containing_address(boot_info.start_address()); + let multiboot_end = Frame::containing_address(boot_info.end_address() - 1); + for frame in Frame::range_inclusive(multiboot_start, multiboot_end) { + mapper.identity_map(frame, PRESENT, allocator); + } + debug!("{:?}", mapper); + }); + + let old_table = active_table.switch(new_table); + println!("NEW TABLE!!!"); + + // turn the old p4 page into a guard page + let old_p4_page = Page::containing_address( + old_table.p4_frame.start_address().to_identity_virtual() + ); + active_table.unmap(old_p4_page, allocator); + println!("guard page at {:#x}", old_p4_page.start_address()); + + active_table +} + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Frame { number: usize, diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs index e217e6d..1cb45cf 100644 --- a/src/memory/paging/mod.rs +++ b/src/memory/paging/mod.rs @@ -2,9 +2,7 @@ pub use self::entry::*; pub use self::mapper::Mapper; use core::ops::{Deref, DerefMut, Add}; use super::*; -use multiboot2::BootInformation; -use self::temporary_page::TemporaryPage; -use consts::KERNEL_OFFSET; +pub use self::temporary_page::TemporaryPage; mod entry; mod table; @@ -99,7 +97,7 @@ impl DerefMut for ActivePageTable { } impl ActivePageTable { - unsafe fn new() -> ActivePageTable { + pub unsafe fn new() -> ActivePageTable { ActivePageTable { mapper: Mapper::new(), } @@ -153,7 +151,7 @@ impl ActivePageTable { } pub struct InactivePageTable { - p4_frame: Frame, + pub(in memory) p4_frame: Frame, } impl InactivePageTable { @@ -175,79 +173,6 @@ impl InactivePageTable { } } -pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) - -> ActivePageTable - where A: FrameAllocator -{ - let mut temporary_page = TemporaryPage::new(Page { number: 0xcafebabe }, - allocator); - - let mut active_table = unsafe { ActivePageTable::new() }; - let mut new_table = { - let frame = allocator.allocate_frame().expect("no more frames"); - InactivePageTable::new(frame, &mut active_table, &mut temporary_page) - }; - - active_table.with(&mut new_table, &mut temporary_page, |mapper| { - let elf_sections_tag = boot_info.elf_sections_tag() - .expect("Memory map tag required"); - - for section in elf_sections_tag.sections() { - use self::entry::WRITABLE; - - if !section.is_allocated() { - // section is not loaded to memory - continue; - } - assert!(section.start_address() % PAGE_SIZE == 0, - "sections need to be page aligned"); - - println!("mapping section at addr: {:#x}, size: {:#x}", - section.addr, section.size); - - let flags = EntryFlags::from_elf_section_flags(section); - - fn to_physical_frame(addr: usize) -> Frame { - Frame::containing_address( - if addr < KERNEL_OFFSET { addr } - else { addr - KERNEL_OFFSET }) - } - - let start_frame = to_physical_frame(section.start_address()); - let end_frame = to_physical_frame(section.end_address() - 1); - - for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(frame.start_address().to_kernel_virtual()); - mapper.map_to(page, frame, flags, allocator); - } - } - - // identity map the VGA text buffer - let vga_buffer_frame = Frame::containing_address(0xb8000); - mapper.identity_map(vga_buffer_frame, WRITABLE, allocator); - - // identity map the multiboot info structure - let multiboot_start = Frame::containing_address(boot_info.start_address()); - let multiboot_end = Frame::containing_address(boot_info.end_address() - 1); - for frame in Frame::range_inclusive(multiboot_start, multiboot_end) { - mapper.identity_map(frame, PRESENT, allocator); - } - debug!("{:?}", mapper as *const Mapper); - }); - - let old_table = active_table.switch(new_table); - println!("NEW TABLE!!!"); - - // turn the old p4 page into a guard page - let old_p4_page = Page::containing_address( - old_table.p4_frame.start_address().to_identity_virtual() - ); - active_table.unmap(old_p4_page, allocator); - println!("guard page at {:#x}", old_p4_page.start_address()); - - active_table -} - use core::fmt; use core::fmt::Debug;