|
|
|
@ -1,28 +1,31 @@
|
|
|
|
|
// Depends on kernel
|
|
|
|
|
use crate::memory::{alloc_frame, dealloc_frame};
|
|
|
|
|
use log::*;
|
|
|
|
|
use mips::addr::*;
|
|
|
|
|
use mips::paging::{FrameAllocator, FrameDeallocator};
|
|
|
|
|
use mips::paging::{
|
|
|
|
|
Mapper, PageTable as MIPSPageTable, PageTableEntry, PageTableFlags as EF, TwoLevelPageTable,
|
|
|
|
|
FrameAllocator, FrameDeallocator, Mapper, PageTable as MIPSPageTable, PageTableEntry,
|
|
|
|
|
PageTableFlags as EF, TwoLevelPageTable,
|
|
|
|
|
};
|
|
|
|
|
use mips::tlb::*;
|
|
|
|
|
use mips::tlb::TLBEntry;
|
|
|
|
|
use rcore_memory::paging::*;
|
|
|
|
|
|
|
|
|
|
pub struct ActivePageTable(usize, PageEntry);
|
|
|
|
|
pub struct PageTableImpl {
|
|
|
|
|
page_table: TwoLevelPageTable<'static>,
|
|
|
|
|
root_frame: Frame,
|
|
|
|
|
entry: PageEntry,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// PageTableEntry: the contents of this entry.
|
|
|
|
|
/// Page: this entry is the pte of page `Page`.
|
|
|
|
|
pub struct PageEntry(&'static mut PageTableEntry, Page);
|
|
|
|
|
|
|
|
|
|
impl PageTable for ActivePageTable {
|
|
|
|
|
impl PageTable for PageTableImpl {
|
|
|
|
|
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
|
|
|
|
|
// map the 4K `page` to the 4K `frame` with `flags`
|
|
|
|
|
let flags = EF::VALID | EF::WRITABLE | EF::CACHEABLE;
|
|
|
|
|
let page = Page::of_addr(VirtAddr::new(addr));
|
|
|
|
|
let frame = Frame::of_addr(PhysAddr::new(target));
|
|
|
|
|
// we may need frame allocator to alloc frame for new page table(first/second)
|
|
|
|
|
self.get_table()
|
|
|
|
|
self.page_table
|
|
|
|
|
.map_to(page, frame, flags, &mut FrameAllocatorForMips)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.flush();
|
|
|
|
@ -31,20 +34,29 @@ impl PageTable for ActivePageTable {
|
|
|
|
|
|
|
|
|
|
fn unmap(&mut self, addr: usize) {
|
|
|
|
|
let page = Page::of_addr(VirtAddr::new(addr));
|
|
|
|
|
let (_, flush) = self.get_table().unmap(page).unwrap();
|
|
|
|
|
let (_, flush) = self.page_table.unmap(page).unwrap();
|
|
|
|
|
flush.flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
|
|
|
|
|
let page = Page::of_addr(VirtAddr::new(vaddr));
|
|
|
|
|
if let Ok(e) = self.get_table().ref_entry(page.clone()) {
|
|
|
|
|
if let Ok(e) = self.page_table.ref_entry(page.clone()) {
|
|
|
|
|
let e = unsafe { &mut *(e as *mut PageTableEntry) };
|
|
|
|
|
self.1 = PageEntry(e, page);
|
|
|
|
|
Some(&mut self.1 as &mut Entry)
|
|
|
|
|
self.entry = PageEntry(e, page);
|
|
|
|
|
Some(&mut self.entry as &mut Entry)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_page_slice_mut<'a>(&mut self, addr: usize) -> &'a mut [u8] {
|
|
|
|
|
let frame = self
|
|
|
|
|
.page_table
|
|
|
|
|
.translate_page(Page::of_addr(VirtAddr::new(addr)))
|
|
|
|
|
.unwrap();
|
|
|
|
|
let vaddr = frame.to_kernel_unmapped().as_usize();
|
|
|
|
|
unsafe { core::slice::from_raw_parts_mut(vaddr as *mut u8, 0x1000) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
@ -54,7 +66,7 @@ extern "C" {
|
|
|
|
|
|
|
|
|
|
pub fn set_root_page_table_ptr(ptr: usize) {
|
|
|
|
|
unsafe {
|
|
|
|
|
clear_all_tlb();
|
|
|
|
|
TLBEntry::clear_all();
|
|
|
|
|
*(_root_page_table_ptr as *mut usize) = ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -67,35 +79,11 @@ pub fn root_page_table_buffer() -> &'static mut MIPSPageTable {
|
|
|
|
|
unsafe { &mut *(_root_page_table_ptr as *mut MIPSPageTable) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PageTableExt for ActivePageTable {}
|
|
|
|
|
|
|
|
|
|
static mut __page_table_with_mode: bool = false;
|
|
|
|
|
|
|
|
|
|
/// The virtual address of root page table
|
|
|
|
|
|
|
|
|
|
impl ActivePageTable {
|
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
|
ActivePageTable(get_root_page_table_ptr(), ::core::mem::uninitialized())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn get_raw_table(&mut self) -> *mut MIPSPageTable {
|
|
|
|
|
if __page_table_with_mode {
|
|
|
|
|
get_root_page_table_ptr() as *mut MIPSPageTable
|
|
|
|
|
} else {
|
|
|
|
|
self.0 as *mut MIPSPageTable
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_table(&mut self) -> TwoLevelPageTable<'static> {
|
|
|
|
|
unsafe { TwoLevelPageTable::new(&mut *self.get_raw_table()) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
|
|
|
|
|
impl Entry for PageEntry {
|
|
|
|
|
fn update(&mut self) {
|
|
|
|
|
unsafe {
|
|
|
|
|
clear_all_tlb();
|
|
|
|
|
TLBEntry::clear_all();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn accessed(&self) -> bool {
|
|
|
|
@ -158,22 +146,33 @@ impl Entry for PageEntry {
|
|
|
|
|
fn set_mmio(&mut self, _value: u8) {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct InactivePageTable0 {
|
|
|
|
|
root_frame: Frame,
|
|
|
|
|
impl PageTableImpl {
|
|
|
|
|
/// Unsafely get the current active page table.
|
|
|
|
|
/// WARN: You MUST call `core::mem::forget` for it after use!
|
|
|
|
|
pub unsafe fn active() -> Self {
|
|
|
|
|
let frame = Frame::of_addr(PhysAddr::new(get_root_page_table_ptr() & 0x7fffffff));
|
|
|
|
|
let table = root_page_table_buffer();
|
|
|
|
|
PageTableImpl {
|
|
|
|
|
page_table: TwoLevelPageTable::new(table),
|
|
|
|
|
root_frame: frame,
|
|
|
|
|
entry: unsafe { core::mem::uninitialized() },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InactivePageTable for InactivePageTable0 {
|
|
|
|
|
type Active = ActivePageTable;
|
|
|
|
|
|
|
|
|
|
impl PageTableExt for PageTableImpl {
|
|
|
|
|
fn new_bare() -> Self {
|
|
|
|
|
let target = alloc_frame().expect("failed to allocate frame");
|
|
|
|
|
let frame = Frame::of_addr(PhysAddr::new(target));
|
|
|
|
|
|
|
|
|
|
let table = unsafe { &mut *(target as *mut MIPSPageTable) };
|
|
|
|
|
|
|
|
|
|
table.zero();
|
|
|
|
|
InactivePageTable0 { root_frame: frame }
|
|
|
|
|
|
|
|
|
|
PageTableImpl {
|
|
|
|
|
page_table: TwoLevelPageTable::new(table),
|
|
|
|
|
root_frame: frame,
|
|
|
|
|
entry: unsafe { core::mem::uninitialized() },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn map_kernel(&mut self) {
|
|
|
|
@ -194,61 +193,12 @@ impl InactivePageTable for InactivePageTable0 {
|
|
|
|
|
|
|
|
|
|
fn flush_tlb() {
|
|
|
|
|
unsafe {
|
|
|
|
|
clear_all_tlb();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
|
|
|
|
|
unsafe {
|
|
|
|
|
clear_all_tlb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"edit table {:x?} -> {:x?}",
|
|
|
|
|
Self::active_token(),
|
|
|
|
|
self.token()
|
|
|
|
|
);
|
|
|
|
|
let mut active = unsafe { ActivePageTable(self.token(), ::core::mem::uninitialized()) };
|
|
|
|
|
|
|
|
|
|
let ret = f(&mut active);
|
|
|
|
|
debug!("finish table");
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
clear_all_tlb();
|
|
|
|
|
}
|
|
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
|
|
|
|
|
let old_token = Self::active_token();
|
|
|
|
|
let new_token = self.token();
|
|
|
|
|
|
|
|
|
|
let old_mode = unsafe { __page_table_with_mode };
|
|
|
|
|
unsafe {
|
|
|
|
|
__page_table_with_mode = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
|
|
|
|
|
if old_token != new_token {
|
|
|
|
|
Self::set_token(new_token);
|
|
|
|
|
Self::flush_tlb();
|
|
|
|
|
TLBEntry::clear_all();
|
|
|
|
|
}
|
|
|
|
|
let ret = f();
|
|
|
|
|
debug!("switch table {:x?} -> {:x?}", new_token, old_token);
|
|
|
|
|
if old_token != new_token {
|
|
|
|
|
Self::set_token(old_token);
|
|
|
|
|
Self::flush_tlb();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
__page_table_with_mode = old_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for InactivePageTable0 {
|
|
|
|
|
impl Drop for PageTableImpl {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
dealloc_frame(self.root_frame.start_address().as_usize());
|
|
|
|
|
}
|
|
|
|
|