|
|
@ -1,20 +1,11 @@
|
|
|
|
use memory::*;
|
|
|
|
use memory::*;
|
|
|
|
//pub use self::cow::*;
|
|
|
|
pub use ucore_memory::paging::{Entry, PageTable};
|
|
|
|
use x86_64::structures::paging::*;
|
|
|
|
|
|
|
|
use x86_64::registers::control::{Cr3, Cr3Flags};
|
|
|
|
|
|
|
|
use x86_64::instructions::tlb;
|
|
|
|
use x86_64::instructions::tlb;
|
|
|
|
|
|
|
|
use x86_64::registers::control::{Cr3, Cr3Flags};
|
|
|
|
|
|
|
|
use x86_64::structures::paging::{Mapper, PageTable as x86PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
|
|
|
|
|
|
|
|
pub use x86_64::structures::paging::{FrameAllocator, FrameDeallocator, Page, PageRange, PhysFrame as Frame, Size4KiB};
|
|
|
|
use x86_64::ux::u9;
|
|
|
|
use x86_64::ux::u9;
|
|
|
|
|
|
|
|
|
|
|
|
pub type Frame = PhysFrame;
|
|
|
|
|
|
|
|
pub type EntryFlags = PageTableFlags;
|
|
|
|
|
|
|
|
pub type ActivePageTable = RecursivePageTable<'static>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub use x86_64::structures::paging::{Page, PageRange, Mapper, FrameAllocator, FrameDeallocator, Size4KiB, PageTable};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//mod cow;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ENTRY_COUNT: usize = 512;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub trait PageExt {
|
|
|
|
pub trait PageExt {
|
|
|
|
fn of_addr(address: VirtAddr) -> Self;
|
|
|
|
fn of_addr(address: VirtAddr) -> Self;
|
|
|
|
fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange;
|
|
|
|
fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange;
|
|
|
@ -40,18 +31,53 @@ impl FrameExt for Frame {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub trait ActiveTableExt {
|
|
|
|
pub struct ActivePageTable(RecursivePageTable<'static>);
|
|
|
|
fn with(&mut self, table: &mut InactivePageTable, f: impl FnOnce(&mut ActivePageTable));
|
|
|
|
|
|
|
|
fn map_to_(&mut self, page: Page, frame: Frame, flags: EntryFlags);
|
|
|
|
pub struct PageEntry(PageTableEntry);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl PageTable for ActivePageTable {
|
|
|
|
|
|
|
|
type Entry = PageEntry;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
|
|
|
|
|
|
|
|
let flags = EF::PRESENT | EF::WRITABLE | EF::NO_EXECUTE;
|
|
|
|
|
|
|
|
self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, &mut frame_allocator())
|
|
|
|
|
|
|
|
.unwrap().flush();
|
|
|
|
|
|
|
|
self.get_entry(addr)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn unmap(&mut self, addr: usize) {
|
|
|
|
|
|
|
|
let (frame, flush) = self.0.unmap(Page::of_addr(addr)).unwrap();
|
|
|
|
|
|
|
|
flush.flush();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_entry(&mut self, addr: usize) -> &mut PageEntry {
|
|
|
|
|
|
|
|
let entry_addr = ((addr >> 9) & 0o777_777_777_7770) | 0xffffff80_00000000;
|
|
|
|
|
|
|
|
unsafe { &mut *(entry_addr as *mut PageEntry) }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn read_page(&mut self, addr: usize, data: &mut [u8]) {
|
|
|
|
|
|
|
|
use core::slice;
|
|
|
|
|
|
|
|
let mem = unsafe { slice::from_raw_parts((addr & !0xfffusize) as *const u8, 4096) };
|
|
|
|
|
|
|
|
data.copy_from_slice(mem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl ActiveTableExt for ActivePageTable {
|
|
|
|
fn write_page(&mut self, addr: usize, data: &[u8]) {
|
|
|
|
fn with(&mut self, table: &mut InactivePageTable, f: impl FnOnce(&mut ActivePageTable)) {
|
|
|
|
use core::slice;
|
|
|
|
with_temporary_map(self, &Cr3::read().0, |active_table, p4_table: &mut PageTable| {
|
|
|
|
let mem = unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, 4096) };
|
|
|
|
|
|
|
|
mem.copy_from_slice(data);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl ActivePageTable {
|
|
|
|
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
|
|
|
|
ActivePageTable(RecursivePageTable::new(&mut *(0xffffffff_fffff000 as *mut _)).unwrap())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn with(&mut self, table: &mut InactivePageTable, f: impl FnOnce(&mut ActivePageTable)) {
|
|
|
|
|
|
|
|
with_temporary_map(self, &Cr3::read().0, |active_table, p4_table: &mut x86PageTable| {
|
|
|
|
let backup = p4_table[0o777].clone();
|
|
|
|
let backup = p4_table[0o777].clone();
|
|
|
|
|
|
|
|
|
|
|
|
// overwrite recursive mapping
|
|
|
|
// overwrite recursive mapping
|
|
|
|
p4_table[0o777].set_frame(table.p4_frame.clone(), EntryFlags::PRESENT | EntryFlags::WRITABLE);
|
|
|
|
p4_table[0o777].set_frame(table.p4_frame.clone(), EF::PRESENT | EF::WRITABLE);
|
|
|
|
tlb::flush_all();
|
|
|
|
tlb::flush_all();
|
|
|
|
|
|
|
|
|
|
|
|
// execute f in the new context
|
|
|
|
// execute f in the new context
|
|
|
@ -62,20 +88,55 @@ impl ActiveTableExt for ActivePageTable {
|
|
|
|
tlb::flush_all();
|
|
|
|
tlb::flush_all();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn map_to_(&mut self, page: Page<Size4KiB>, frame: PhysFrame<Size4KiB>, flags: EntryFlags) {
|
|
|
|
pub fn map_to(&mut self, page: Page, frame: Frame) -> &mut PageEntry {
|
|
|
|
self.map_to(page, frame, flags, &mut frame_allocator()).unwrap().flush();
|
|
|
|
self.map(page.start_address().as_u64() as usize, frame.start_address().as_u64() as usize)
|
|
|
|
|
|
|
|
}
|
|
|
|
// Set user bit for p1-p4 entry
|
|
|
|
}
|
|
|
|
// It's a workaround since x86_64 PageTable do not set user bit.
|
|
|
|
|
|
|
|
if flags.contains(EntryFlags::USER_ACCESSIBLE) {
|
|
|
|
impl Entry for PageEntry {
|
|
|
|
let mut addr = page.start_address().as_u64();
|
|
|
|
fn update(&mut self) {
|
|
|
|
for _ in 0..4 {
|
|
|
|
use x86_64::{VirtAddr, instructions::tlb::flush};
|
|
|
|
|
|
|
|
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
|
|
|
|
|
|
|
|
flush(addr);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) }
|
|
|
|
|
|
|
|
fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
|
|
|
|
|
|
|
|
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) }
|
|
|
|
|
|
|
|
fn present(&self) -> bool { self.0.flags().contains(EF::PRESENT) }
|
|
|
|
|
|
|
|
fn clear_accessed(&mut self) { self.as_flags().remove(EF::ACCESSED); }
|
|
|
|
|
|
|
|
fn clear_dirty(&mut self) { self.as_flags().remove(EF::DIRTY); }
|
|
|
|
|
|
|
|
fn set_writable(&mut self, value: bool) { self.as_flags().set(EF::WRITABLE, value); }
|
|
|
|
|
|
|
|
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::PRESENT, value); }
|
|
|
|
|
|
|
|
fn target(&self) -> usize { self.0.addr().as_u64() as usize }
|
|
|
|
|
|
|
|
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::BIT_10) }
|
|
|
|
|
|
|
|
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::BIT_9) }
|
|
|
|
|
|
|
|
fn set_shared(&mut self, writable: bool) {
|
|
|
|
|
|
|
|
let flags = self.as_flags();
|
|
|
|
|
|
|
|
flags.set(EF::BIT_10, writable);
|
|
|
|
|
|
|
|
flags.set(EF::BIT_9, !writable);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear_shared(&mut self) { self.as_flags().remove(EF::BIT_9 | EF::BIT_10); }
|
|
|
|
|
|
|
|
fn user(&self) -> bool { self.0.flags().contains(EF::USER_ACCESSIBLE) }
|
|
|
|
|
|
|
|
fn set_user(&mut self, value: bool) {
|
|
|
|
|
|
|
|
self.as_flags().set(EF::USER_ACCESSIBLE, value);
|
|
|
|
|
|
|
|
if value {
|
|
|
|
|
|
|
|
let mut addr = self as *const _ as usize;
|
|
|
|
|
|
|
|
for _ in 0..3 {
|
|
|
|
|
|
|
|
// Upper level entry
|
|
|
|
addr = ((addr >> 9) & 0o777_777_777_7770) | 0xffffff80_00000000;
|
|
|
|
addr = ((addr >> 9) & 0o777_777_777_7770) | 0xffffff80_00000000;
|
|
|
|
// set USER_ACCESSIBLE
|
|
|
|
// set USER_ACCESSIBLE
|
|
|
|
unsafe { (*(addr as *mut EntryFlags)).insert(EntryFlags::USER_ACCESSIBLE) };
|
|
|
|
unsafe { (*(addr as *mut EF)).insert(EF::USER_ACCESSIBLE) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute(&self) -> bool { !self.0.flags().contains(EF::NO_EXECUTE) }
|
|
|
|
|
|
|
|
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::NO_EXECUTE, !value); }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl PageEntry {
|
|
|
|
|
|
|
|
fn as_flags(&mut self) -> &mut EF {
|
|
|
|
|
|
|
|
unsafe { &mut *(self as *mut _ as *mut EF) }
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
@ -85,13 +146,23 @@ pub struct InactivePageTable {
|
|
|
|
|
|
|
|
|
|
|
|
impl InactivePageTable {
|
|
|
|
impl InactivePageTable {
|
|
|
|
pub fn new(frame: Frame, active_table: &mut ActivePageTable) -> InactivePageTable {
|
|
|
|
pub fn new(frame: Frame, active_table: &mut ActivePageTable) -> InactivePageTable {
|
|
|
|
with_temporary_map(active_table, &frame, |_, table: &mut PageTable| {
|
|
|
|
with_temporary_map(active_table, &frame, |_, table: &mut x86PageTable| {
|
|
|
|
table.zero();
|
|
|
|
table.zero();
|
|
|
|
// set up recursive mapping for the table
|
|
|
|
// set up recursive mapping for the table
|
|
|
|
table[511].set_frame(frame.clone(), EntryFlags::PRESENT | EntryFlags::WRITABLE);
|
|
|
|
table[511].set_frame(frame.clone(), EF::PRESENT | EF::WRITABLE);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
InactivePageTable { p4_frame: frame }
|
|
|
|
InactivePageTable { p4_frame: frame }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn map_kernel(&mut self, active_table: &mut ActivePageTable) {
|
|
|
|
|
|
|
|
let mut table = unsafe { &mut *(0xffffffff_fffff000 as *mut x86PageTable) };
|
|
|
|
|
|
|
|
let e510 = table[510].clone();
|
|
|
|
|
|
|
|
let e509 = table[509].clone();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
active_table.with(self, |pt: &mut ActivePageTable| {
|
|
|
|
|
|
|
|
table[510] = e510;
|
|
|
|
|
|
|
|
table[509] = e509;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
pub fn switch(&self) {
|
|
|
|
pub fn switch(&self) {
|
|
|
|
let old_frame = Cr3::read().0;
|
|
|
|
let old_frame = Cr3::read().0;
|
|
|
|
let new_frame = self.p4_frame.clone();
|
|
|
|
let new_frame = self.p4_frame.clone();
|
|
|
@ -112,15 +183,15 @@ impl Drop for InactivePageTable {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn with_temporary_map(active_table: &mut ActivePageTable, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut PageTable)) {
|
|
|
|
fn with_temporary_map(active_table: &mut ActivePageTable, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut x86PageTable)) {
|
|
|
|
// Create a temporary page
|
|
|
|
// Create a temporary page
|
|
|
|
let page = Page::of_addr(0xcafebabe);
|
|
|
|
let page = Page::of_addr(0xcafebabe);
|
|
|
|
assert!(active_table.translate_page(page).is_none(), "temporary page is already mapped");
|
|
|
|
assert!(active_table.0.translate_page(page).is_none(), "temporary page is already mapped");
|
|
|
|
// Map it to table
|
|
|
|
// Map it to table
|
|
|
|
active_table.map_to_(page, frame.clone(), EntryFlags::PRESENT | EntryFlags::WRITABLE);
|
|
|
|
active_table.map_to(page, frame.clone());
|
|
|
|
// Call f
|
|
|
|
// Call f
|
|
|
|
let table = unsafe { &mut *page.start_address().as_mut_ptr() };
|
|
|
|
let table = unsafe { &mut *page.start_address().as_mut_ptr() };
|
|
|
|
f(active_table, table);
|
|
|
|
f(active_table, table);
|
|
|
|
// Unmap the page
|
|
|
|
// Unmap the page
|
|
|
|
active_table.unmap(page).unwrap().1.flush();
|
|
|
|
active_table.unmap(0xcafebabe);
|
|
|
|
}
|
|
|
|
}
|