From f4a8ca726129ef92e8172d2418eb6017b2d65f43 Mon Sep 17 00:00:00 2001 From: Mahdi Dibaiee Date: Mon, 11 Jul 2016 10:43:02 +0430 Subject: [PATCH] fix(paging): translating addresses --- src/memory/mod.rs | 6 +-- src/memory/paging/entry.rs | 3 +- src/memory/paging/mod.rs | 97 ++++++++++++++++++++++++++++++++++++++ src/memory/paging/table.rs | 42 +++++++++++------ 4 files changed, 130 insertions(+), 18 deletions(-) diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 0757a75..95b00a0 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -1,9 +1,9 @@ +mod paging; +mod area_frame_allocator; + pub use self::area_frame_allocator::AreaFrameAllocator; use self::paging::PhysicalAddress; -mod area_frame_allocator; -mod paging; - pub const PAGE_SIZE: usize = 4096; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/memory/paging/entry.rs b/src/memory/paging/entry.rs index e507540..6d89448 100644 --- a/src/memory/paging/entry.rs +++ b/src/memory/paging/entry.rs @@ -1,4 +1,5 @@ use memory::PAGE_SIZE; +use memory::Frame; pub struct Entry(u64); @@ -26,7 +27,7 @@ impl Entry { } pub fn set (&mut self, frame: Frame, flags: EntryFlags) { - assert!(frame.start_address() & !x000fffff_fffff000 == 0); + assert!(frame.start_address() & !0x000fffff_fffff000 == 0); self.0 = (frame.start_address() as u64) | flags.bits(); } } diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs index 03c32a0..a6f2253 100644 --- a/src/memory/paging/mod.rs +++ b/src/memory/paging/mod.rs @@ -1,8 +1,73 @@ +mod entry; +mod table; + use memory::PAGE_SIZE; use memory::Frame; +pub use self::entry::*; +use memory::FrameAllocator; +use self::table::*; const ENTRY_COUNT: usize = 512; +pub fn map_to(page: Page, frame: Frame, flags: EntryFlags, allocator: &mut A) + where A: FrameAllocator +{ + let p4 = unsafe { &mut *P4 }; + let mut p3 = p4.next_table_create(page.p4_index(), allocator); + let mut p2 = p3.next_table_create(page.p3_index(), allocator); + let mut p1 = p2.next_table_create(page.p2_index(), allocator); + + assert!(p1[page.p1_index()].is_unused()); + p1[page.p1_index()].set(frame, flags | PRESENT); +} + +pub fn translate(virtual_address: VirtualAddress) -> Option { + let offset = virtual_address & PAGE_SIZE; + translate_page(Page::containing_address(virtual_address)) + .map(|frame| frame.number * PAGE_SIZE + offset) +} + +pub fn translate_page(page: Page) -> Option { + use self::entry::HUGE_PAGE; + + let p3 = unsafe { &*table::P4 }.next_table(page.p4_index()); + let huge_page = || { + p3.and_then(|p3| { + let p3_entry = &p3[page.p3_index()]; + + // 1GiB page? + if let Some(start_frame) = p3_entry.pointed_frame() { + if p3_entry.flags().contains(HUGE_PAGE) { + // address must be 1GiB aligned + assert!(start_frame.number % (ENTRY_COUNT * ENTRY_COUNT) == 0); + return Some(Frame { + number: start_frame.number + page.p2_index() * ENTRY_COUNT + page.p1_index(), + }); + } + } + + if let Some(p2) = p3.next_table(page.p3_index()) { + let p2_entry = &p2[page.p2_index()]; + // 2MiB page? + if let Some(start_frame) = p2_entry.pointed_frame() { + if p2_entry.flags().contains(HUGE_PAGE) { + // address must be 2MiB aligned + assert!(start_frame.number % ENTRY_COUNT == 0); + return Some(Frame { number: start_frame.number + page.p1_index() }); + } + } + } + + None + }) + }; + + p3.and_then(|p3| p3.next_table(page.p3_index())) + .and_then(|p2| p2.next_table(page.p2_index())) + .and_then(|p1| p1[page.p1_index()].pointed_frame()) + .or_else(huge_page) +} + pub type PhysicalAddress = usize; pub type VirtualAddress = usize; @@ -10,6 +75,37 @@ pub struct Page { number: usize, } +impl Page { + pub fn containing_address(address: VirtualAddress) -> Page { + assert!(address < 0x0000_8000_0000_0000 || + address >= 0xffff_8000_0000_0000, + "invalid address: 0x{:x}", address); + + Page { number: address / PAGE_SIZE } + } + + fn start_address(&self) -> usize { + self.number * PAGE_SIZE + } + + fn p4_index(&self) -> usize { + (self.number >> 27) & 0o777 + } + + fn p3_index(&self) -> usize { + (self.number >> 18) & 0o777 + } + + fn p2_index(&self) -> usize { + (self.number >> 9) & 0o777 + } + + fn p1_index(&self) -> usize { + (self.number >> 0) & 0o777 + } +} + +/* pub struct Entry(u64); impl Entry { @@ -55,3 +151,4 @@ bitflags! { const NO_EXECUTE = 1 << 63, } } +*/ diff --git a/src/memory/paging/table.rs b/src/memory/paging/table.rs index d3e1cc2..faa07c3 100644 --- a/src/memory/paging/table.rs +++ b/src/memory/paging/table.rs @@ -1,33 +1,37 @@ use memory::paging::entry::*; use memory::paging::ENTRY_COUNT; +use memory::FrameAllocator; use core::ops::{Index, IndexMut}; use core::marker::PhantomData; pub const P4: *mut Table = 0xffffffff_fffff000 as *mut _; pub trait TableLevel {} -pub enum Level 4 {} -pub enum Level 3 {} -pub enum Level 2 {} -pub enum Level 1 {} +pub enum Level4 {} +#[allow(dead_Code)] +pub enum Level3 {} +#[allow(dead_Code)] +pub enum Level2 {} +pub enum Level1 {} impl TableLevel for Level4 {} impl TableLevel for Level3 {} impl TableLevel for Level2 {} impl TableLevel for Level1 {} + pub trait HierarchicalLevel: TableLevel { type NextLevel: TableLevel; } impl HierarchicalLevel for Level4 { - type NextLevel: Level3 + type NextLevel = Level3; } impl HierarchicalLevel for Level3 { - type NextLevel: Level2 + type NextLevel = Level2; } impl HierarchicalLevel for Level2 { - type NextLevel: Level1 + type NextLevel = Level1; } pub struct Table { @@ -64,6 +68,23 @@ impl Table where L: HierarchicalLevel { self.next_table_address(index) .map(|address| unsafe { &mut *(address as *mut _) }) } + + pub fn next_table_create(&mut self, index: usize, allocator: &mut A) + -> &mut Table + where A: FrameAllocator + { + if self.next_table(index).is_none() { + assert!(!self.entries[index].flags().contains(HUGE_PAGE), + "mapping code does not support huge pages"); + + let frame = allocator.allocate_frame().expect("no frames available"); + + self.entries[index].set(frame, PRESENT | WRITABLE); + self.next_table_mut(index).unwrap().zero(); + } + + self.next_table_mut(index).unwrap() + } } impl Index for Table where L: TableLevel { @@ -80,10 +101,3 @@ impl IndexMut for Table where L: TableLevel { } } -fn test() { - let p4 = unsafe { &*P4 }; - p4.next_table(4@) - .and_then(|p3| p3.next_table(1337)) - .and_then(|p2| p2.next_table(0xdeadbeaf)) - .and_then(|p1| p1.next_table(0xcafebabe)) -}