fix paging for mips

master
WangRunji 6 years ago
parent cd22273ef9
commit c8262f936f

@ -11,30 +11,19 @@ pub struct Page {
}
impl Page {
/*
** @brief get the virtual address of beginning of the page
** @retval VirtAddr the virtual address of beginning of the page
*/
/// Returns the start address of the page.
pub fn start_address(&self) -> VirtAddr {
self.number * PAGE_SIZE
}
/*
** @brief get the page of a given virtual address
** @param addr: VirtAddr the given virtual address
** @retval Page the page of the given virtual address
*/
/// Returns the page that contains the given virtual address.
pub fn of_addr(addr: VirtAddr) -> Self {
Page {
number: addr / PAGE_SIZE,
}
}
/*
** @brief get a pageRange between two virtual address
** @param begin: VirtAddr the virtual address of the beginning
** @param end: VirtAddr the virtual address of the end
** @retval PageRange the page of the given virtual address
*/
/// Returns a range of pages between address `begin` and `end`
pub fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange {
PageRange {
start: Page::of_addr(begin),
@ -79,45 +68,3 @@ impl Iterator for PageRange {
}
}
}
/// frame for the swapmanager
#[derive(Debug, Copy, Clone, PartialOrd, Ord)]
#[repr(C)]
pub struct Frame {
/// the raw pointer for the frame's memory set's inactive page table
page_table: usize,
/// the virtual addr for the frame
virtaddr: VirtAddr,
/// the token for frame
token: usize,
}
impl Frame {
pub fn get_page_table(&self) -> usize {
self.page_table
}
pub fn get_virtaddr(&self) -> VirtAddr {
self.virtaddr
}
pub fn get_token(&self) -> usize {
self.token
}
pub fn new(pt: usize, addr: VirtAddr, pttoken: usize) -> Self {
Frame {
page_table: pt,
virtaddr: addr,
token: pttoken,
}
}
}
impl PartialEq for Frame {
fn eq(&self, other: &Frame) -> bool {
self.token == other.token && self.virtaddr == other.virtaddr
}
}
impl Eq for Frame {}

@ -5,16 +5,13 @@ pub trait MemoryHandler: Debug + Send + Sync + 'static {
fn box_clone(&self) -> Box<MemoryHandler>;
/// Map `addr` in the page table
/// Should set page flags here instead of in page_fault_handler
/// Should set page flags here instead of in `page_fault_handler`
fn map(&self, pt: &mut PageTable, addr: VirtAddr, attr: &MemoryAttr);
/// Unmap `addr` in the page table
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr);
/// Clone map `addr` from one page table to another.
/// `pt` is the current active page table.
/// `with` is the `InactivePageTable::with` function.
/// Call `with` then use `pt` as target page table inside.
/// Clone map `addr` from page table `src_pt` to `pt`.
fn clone_map(
&self,
pt: &mut PageTable,

@ -2,12 +2,11 @@
///
pub use super::board::consts::*;
pub const MEMORY_OFFSET: usize = 0x80000000;
pub const KERNEL_OFFSET: usize = 0x80100000;
pub const MEMORY_OFFSET: usize = 0x8000_0000;
pub const PHYSICAL_MEMORY_OFFSET: usize = 0x80000000;
pub const USER_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0x70000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000;

@ -232,7 +232,7 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool {
let tls = unsafe { *(_cur_tls as *const usize) };
set_trapframe_register(rt, tls, tf);
info!("Read TLS by rdhdr {:x} to register {:?}", tls, rt);
debug!("Read TLS by rdhdr {:x} to register {:?}", tls, rt);
return true;
} else {
return false;

@ -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());
}

Loading…
Cancel
Save