fix(paging): translating addresses
This commit is contained in:
parent
23fe830220
commit
f4a8ca7261
@ -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)]
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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<A>(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<PhysicalAddress> {
|
||||
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<Frame> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -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<Level4> = 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<L: TableLevel> {
|
||||
@ -64,6 +68,23 @@ impl<L> Table<L> where L: HierarchicalLevel {
|
||||
self.next_table_address(index)
|
||||
.map(|address| unsafe { &mut *(address as *mut _) })
|
||||
}
|
||||
|
||||
pub fn next_table_create<A>(&mut self, index: usize, allocator: &mut A)
|
||||
-> &mut Table<L::NextLevel>
|
||||
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<L> Index<usize> for Table<L> where L: TableLevel {
|
||||
@ -80,10 +101,3 @@ impl<L> IndexMut<usize> for Table<L> 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))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user