diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index fa9f34ca..6ababe05 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -178,7 +178,7 @@ pub fn acpi_info() -> Result <(), &'static str> { pub fn regs() -> Result <(), &'static str> { use x86::registers::control::*; println!("cr0={:#b}", Cr0::read()); - println!("cr3={:#x}", Cr3::read()); + println!("cr3={:?}", Cr3::read()); // TODO implement cr4 flags in `x86` module // println!("cr4={:#b}", Cr4::read()); Ok(()) diff --git a/kernel-rs/src/memory/area_allocator.rs b/kernel-rs/src/memory/area_allocator.rs index 011f6cb4..6a24bb94 100644 --- a/kernel-rs/src/memory/area_allocator.rs +++ b/kernel-rs/src/memory/area_allocator.rs @@ -1,5 +1,6 @@ use memory::*; use multiboot2::{MemoryAreaIter, MemoryArea}; +use x86::*; pub struct AreaFrameAllocator { next_free_frame: PhysFrame, @@ -16,13 +17,17 @@ impl AreaFrameAllocator { multiboot_start: usize, multiboot_end: usize, memory_areas: MemoryAreaIter) -> AreaFrameAllocator { let mut allocator = AreaFrameAllocator { - next_free_frame: PhysFrame::containing_address(0), + next_free_frame: PhysFrame { number: 0 }, current_area: None, areas: memory_areas, - kernel_start: PhysFrame::containing_address(kernel_start), - kernel_end: PhysFrame::containing_address(kernel_end), - multiboot_start: PhysFrame::containing_address(multiboot_start), - multiboot_end: PhysFrame::containing_address(multiboot_end), + kernel_start: PhysFrame::containing_address( + PhysAddr::new(kernel_start as u32)), + kernel_end: PhysFrame::containing_address( + PhysAddr::new(kernel_end as u32)), + multiboot_start: PhysFrame::containing_address( + PhysAddr::new(multiboot_start as u32)), + multiboot_end: PhysFrame::containing_address( + PhysAddr::new(multiboot_end as u32)), }; allocator.choose_next_area(); allocator @@ -31,11 +36,12 @@ impl AreaFrameAllocator { fn choose_next_area(&mut self) { // get next area with free frames self.current_area = self.areas.clone().filter(|area| { - PhysFrame::containing_address(area.end_address()) >= self.next_free_frame + area.end_address() >= self.next_free_frame.start_address().as_u32() as usize }).min_by_key(|area| area.start_address()); if let Some(area) = self.current_area { - let start_frame = PhysFrame::containing_address(area.start_address()); + let start_frame = PhysFrame::containing_address( + PhysAddr::new(area.start_address() as u32)); if self.next_free_frame < start_frame { self.next_free_frame = start_frame; } @@ -45,9 +51,10 @@ impl AreaFrameAllocator { impl FrameAllocator for AreaFrameAllocator { fn allocate_frame(&mut self) -> Option { - if let Some(area) = self.current_arPhysea { + if let Some(area) = self.current_area { let frame = PhysFrame { number: self.next_free_frame.number }; - let current_area_last_frame = PhysFrame::containing_address(area.end_address()); + let current_area_last_frame = PhysFrame::containing_address( + PhysAddr::new(area.end_address() as u32)); if frame > current_area_last_frame { // all frames are taken in this area self.choose_next_area(); diff --git a/kernel-rs/src/memory/mod.rs b/kernel-rs/src/memory/mod.rs index 89568f0b..c2a6c244 100644 --- a/kernel-rs/src/memory/mod.rs +++ b/kernel-rs/src/memory/mod.rs @@ -8,7 +8,7 @@ pub use self::area_allocator::*; pub use self::heap_allocator::*; pub use self::paging::remap_the_kernel; use multiboot2; - +use x86::*; use x86::structures::paging::*; pub trait FrameAllocator { @@ -16,25 +16,6 @@ pub trait FrameAllocator { fn deallocate_frame(&mut self, frame: PhysFrame); } -struct FrameIter { - start: PhysFrame, - end: PhysFrame, -} - -impl Iterator for FrameIter { - type Item = PhysFrame; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let frame = self.start.clone(); - self.start.number += 1; - Some(frame) - } else { - None - } - } -} - /// memory initialisation should only be called once pub fn init(boot_info: &multiboot2::BootInformation) { let elf_sections_tag = boot_info.elf_sections_tag().unwrap(); @@ -59,10 +40,12 @@ pub fn init(boot_info: &multiboot2::BootInformation) { boot_info); use {HEAP_START, HEAP_SIZE}; - let heap_start_page = Page::containing_address(HEAP_START); - let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1); + let heap_start_page = Page::containing_address( + VirtAddr::new(HEAP_START as u32)); + let heap_end_page = Page::containing_address( + VirtAddr::new(HEAP_START as u32 + HEAP_SIZE as u32 - 1)); - for page in Page::range_inclusive(heap_start_page, heap_end_page) { + for page in heap_start_page..heap_end_page { active_table.map(page, PageTableFlags::WRITABLE, &mut frame_allocator); } } diff --git a/kernel-rs/src/memory/paging/mapper.rs b/kernel-rs/src/memory/paging/mapper.rs index 27800c23..d8be6889 100644 --- a/kernel-rs/src/memory/paging/mapper.rs +++ b/kernel-rs/src/memory/paging/mapper.rs @@ -3,7 +3,8 @@ use core::ptr::Unique; use x86::structures::paging::*; use x86::instructions::tlb; use x86::*; -// +use super::paging::table::RecTable; + // virtual address of recursively mapped P2 // for protected mode non PAE // https://wiki.osdev.org/Page_Tables @@ -29,6 +30,7 @@ impl Mapper { unsafe { self.p2.as_mut() } } + /// virtual addr to physical addr translation pub fn translate(&self, virtual_address: VirtAddr) -> Option { let offset = virtual_address.as_u32() % PAGE_SIZE as u32; @@ -37,15 +39,26 @@ impl Mapper { } + /// virtual page to physical frame translation pub fn translate_page(&self, page: Page) -> Option { + let p1 = self.p2().next_table(page.p2_index()); - let p1 = self.p2()[page.p2_index()].points_to() - .and_then(|paddr| PageTable::from(paddr)); + let huge_page = || { + let p2_entry = &self.p2()[page.p2_index()]; + if let Some(start_frame) = p2_entry.pointed_frame() { + if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) { + // TODO 4MiB alignment check + return Some(start_frame + u32::from(page.p1_index())); + } + } + None + }; - p1.and_then() + p1.and_then(|p1| p1[page.p1_index()].pointed_frame()) + .or_else(huge_page) } - + /// map a virtual page to a physical frame in the page tables pub fn map_to(&mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, allocator: &mut A) where A: FrameAllocator diff --git a/kernel-rs/src/memory/paging/mod.rs b/kernel-rs/src/memory/paging/mod.rs index c5363e1e..39785015 100644 --- a/kernel-rs/src/memory/paging/mod.rs +++ b/kernel-rs/src/memory/paging/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -// mod table; +mod table; mod temporary_page; mod mapper; @@ -9,28 +9,9 @@ use self::mapper::Mapper; use self::temporary_page::TemporaryPage; use core::ops::{Deref, DerefMut}; use multiboot2::BootInformation; -use x86; +use x86::*; use x86::registers::control::Cr3; - -#[derive(Clone)] -pub struct PageIter { - start: Page, - end: Page, -} - -impl Iterator for PageIter { - type Item = Page; - - fn next(&mut self) -> Option { - if self.start <= self.end { - let page = self.start; - self.start.number += 1; - Some(page) - } else { - None - } - } -} +use x86::instructions::tlb; pub struct ActivePageTable { mapper: Mapper, @@ -63,14 +44,14 @@ impl ActivePageTable { f: F) where F: FnOnce(&mut Mapper) { - let (cr3_back, cr3flags_back) = Cr3::read(); + let (cr3_back, _cr3flags_back) = Cr3::read(); // map temp page to current p2 let p2_table = temporary_page.map_table_frame(cr3_back.clone(), self); // overwrite recursive map self.p2_mut()[1023].set(table.p2_frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE); - x86::instructions::tlb::flush_all(); + tlb::flush_all(); // execute f in the new context f(self); @@ -80,17 +61,9 @@ impl ActivePageTable { } pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { - - let p2_frame = PhysFrame::containing_address(Cr3::read() as usize); - - let old_table = InactivePageTable { - p2_frame, - }; - - unsafe { - let frame = PhysFrame::containing_address(new_table.p2_frame.start_address()); - Cr3::write(frame.start_address()); - } + let (p2_frame, cr3_flags) = Cr3::read(); + let old_table = InactivePageTable { p2_frame }; + unsafe { Cr3::write(new_table.p2_frame, cr3_flags); } old_table } @@ -103,19 +76,27 @@ pub struct InactivePageTable { impl InactivePageTable { pub fn new(frame: PhysFrame, active_table: &mut ActivePageTable, - temporary_page: &mut TemporaryPage, - ) -> InactivePageTable { + temporary_page: &mut TemporaryPage) + -> InactivePageTable { { - let table = temporary_page.map_table_frame(frame.clone(), - active_table); - table.zero(); + let table = temporary_page.map_table_frame(frame.clone(), active_table); + // table.zero(); + let iter = table.entries.iter_mut(); + for entry in iter { + println!("entry = {:?}", entry as *const _); + // println!("entry = {:?}", entry.flags()); + } + + println!("frame = {:?}", frame); + flush!(); + loop {} // set up recursive mapping for the table table[1023].set(frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE) } temporary_page.unmap(active_table); InactivePageTable { p2_frame: frame } - } + } } pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) @@ -133,7 +114,7 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) active_table.with(&mut new_table, &mut temporary_page, |mapper| { // identity map the VGA text buffer - let vga_buffer_frame = PhysFrame::containing_address(0xb8000); + let vga_buffer_frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); mapper.identity_map(vga_buffer_frame, PageTableFlags::WRITABLE, allocator); let elf_sections_tag = boot_info.elf_sections_tag() @@ -146,24 +127,53 @@ pub fn remap_the_kernel(allocator: &mut A, boot_info: &BootInformation) assert!(section.start_address() % PAGE_SIZE as u64 == 0, "sections need to be page aligned"); - let flags = PageTableFlags::from_elf_section_flags(§ion); - let start_frame = PhysFrame::containing_address(section.start_address() as usize); - let end_frame = PhysFrame::containing_address(section.end_address() as usize - 1); - for frame in PhysFrame::range_inclusive(start_frame, end_frame) { + let flags = elf_to_pagetable_flags(§ion.flags()); + let start_frame = PhysFrame::containing_address( + PhysAddr::new(section.start_address() as u32)); + let end_frame = PhysFrame::containing_address( + PhysAddr::new(section.end_address() as u32 - 1)); + for frame in start_frame..end_frame { mapper.identity_map(frame, flags, allocator); } } - let multiboot_start = PhysFrame::containing_address(boot_info.start_address()); - let multiboot_end = PhysFrame::containing_address(boot_info.end_address() - 1); - for frame in PhysFrame::range_inclusive(multiboot_start, multiboot_end) { + let multiboot_start = PhysFrame::containing_address( + PhysAddr::new(boot_info.start_address() as u32)); + let multiboot_end = PhysFrame::containing_address( + PhysAddr::new(boot_info.end_address() as u32 - 1)); + for frame in multiboot_start..multiboot_end { mapper.identity_map(frame, PageTableFlags::PRESENT, allocator); } }); + let old_table = active_table.switch(new_table); - let old_p2_page = Page::containing_address(old_table.p2_frame.start_address()); + let old_p2_page = Page::containing_address( + VirtAddr::new(old_table.p2_frame.start_address().as_u32())); active_table.unmap(old_p2_page, allocator); active_table } + +fn elf_to_pagetable_flags(elf_flags: &multiboot2::ElfSectionFlags) + -> PageTableFlags +{ + use multiboot2::ElfSectionFlags; + + let mut flags = PageTableFlags::empty(); + + if elf_flags.contains(ElfSectionFlags::ALLOCATED) { + // section is loaded to memory + flags = flags | PageTableFlags::PRESENT; + } + if elf_flags.contains(ElfSectionFlags::WRITABLE) { + flags = flags | PageTableFlags::WRITABLE; + } + + // LONG MODE STUFF + // if !elf_flags.contains(ELF_SECTION_EXECUTABLE) { + // flags = flags | PageTableFlags::NO_EXECUTE; + // } + + flags +} diff --git a/kernel-rs/src/memory/paging/table.rs b/kernel-rs/src/memory/paging/table.rs index d7aa7554..916813c9 100644 --- a/kernel-rs/src/memory/paging/table.rs +++ b/kernel-rs/src/memory/paging/table.rs @@ -1,23 +1,43 @@ use memory::*; use x86::structures::paging::*; +use x86::ux::*; - -pub trait TableNext - where A: FrameAllocator +pub trait RecTable { - fn next_table_address(&self, index: usize) -> Option; - fn next_table(&self, index: usize) -> Option<&PageTable>; - fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>; - fn next_table_create(&mut self, - index: usize, - allocator: &mut A) -> &mut PageTable; + fn next_table_address(&self, index: u10) -> Option; + fn next_table(&self, index: u10) -> Option<&PageTable>; + fn next_table_mut(&mut self, index: u10) -> Option<&mut PageTable>; + fn next_table_create(&mut self, + index: u10, + allocator: &mut A) + -> &mut PageTable; } -impl TableNext<> for PageTable +impl RecTable for PageTable { + fn next_table_address(&self, index: u10) -> Option { + let entry_flags = self[index].flags(); + if entry_flags.contains(PageTableFlags::PRESENT) && !entry_flags.contains(PageTableFlags::HUGE_PAGE) { + let table_address = self as *const _ as u32; + Some(table_address << 10 | u32::from(index << 12)) + } else { + None + } + } + + fn next_table(&self, index: u10) -> Option<&PageTable> { + self.next_table_address(index) + .map(|address| unsafe { &*(address as *const _) }) + } + + fn next_table_mut(&mut self, index: u10) -> Option<&mut PageTable> { + self.next_table_address(index) + .map(|address| unsafe { &mut *(address as *mut _) }) + } + fn next_table_create(&mut self, - index: usize, - allocator: &mut A) -> &mut PageTable + index: u10, + allocator: &mut A) -> &mut PageTable where A: FrameAllocator { if self.next_table(index).is_none() { diff --git a/kernel-rs/src/memory/paging/temporary_page.rs b/kernel-rs/src/memory/paging/temporary_page.rs index caab2d6a..709fcbfb 100644 --- a/kernel-rs/src/memory/paging/temporary_page.rs +++ b/kernel-rs/src/memory/paging/temporary_page.rs @@ -4,7 +4,7 @@ use x86::*; use x86::structures::paging::*; pub struct TemporaryPage { - page: Page, + pub page: Page, allocator: TinyAllocator, } @@ -26,6 +26,11 @@ impl TemporaryPage { assert!(active_table.translate_page(self.page).is_none(), "temporary page is already mapped"); active_table.map_to(self.page, frame, PageTableFlags::WRITABLE, &mut self.allocator); + // this kind of check should be done in a test routine + assert!(active_table.translate_page(self.page).is_some(), + "temporary page was not mapped"); + println!("trans = {:?}", active_table.translate_page(self.page)); + println!("page = {:?}", self.page.start_address()); self.page.start_address() } @@ -40,7 +45,7 @@ impl TemporaryPage { frame: PhysFrame, active_table: &mut ActivePageTable) -> &mut PageTable { - unsafe { &mut *(self.map(frame, active_table) as *mut PageTable) } + unsafe { &mut *(self.map(frame, active_table).as_u32() as *mut PageTable) } } } diff --git a/kernel-rs/x86 b/kernel-rs/x86 index dc9eb5ce..eae47083 160000 --- a/kernel-rs/x86 +++ b/kernel-rs/x86 @@ -1 +1 @@ -Subproject commit dc9eb5ceb8981848d95e0ddd7040fb86ec9999e3 +Subproject commit eae470839b1ff232dbc4af5389e9a0b4fffe4b30