Kernel remapped.
This commit is contained in:
parent
e37e5708e4
commit
b6f4327a3f
9 changed files with 489 additions and 29 deletions
|
@ -11,6 +11,7 @@ riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
|||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||
buddy_system_allocator = "0.6"
|
||||
spin = "0.7.0"
|
||||
bitflags = "1.2.1"
|
||||
|
||||
[features]
|
||||
board_qemu = []
|
||||
|
|
|
@ -29,11 +29,9 @@ _num_app:
|
|||
.quad {}"#, apps.len())?;
|
||||
|
||||
for i in 0..apps.len() {
|
||||
writeln!(f, r#"
|
||||
.quad app_{}_start"#, i)?;
|
||||
writeln!(f, r#".quad app_{}_start"#, i)?;
|
||||
}
|
||||
writeln!(f, r#"
|
||||
.quad app_{}_end"#, apps.len() - 1)?;
|
||||
writeln!(f, r#".quad app_{}_end"#, apps.len() - 1)?;
|
||||
|
||||
for (idx, app) in apps.iter().enumerate() {
|
||||
println!("app_{}: {}", idx, app);
|
||||
|
|
|
@ -29,6 +29,7 @@ SECTIONS
|
|||
|
||||
. = ALIGN(4K);
|
||||
edata = .;
|
||||
sbss_with_stack = .;
|
||||
.bss : {
|
||||
*(.bss.stack)
|
||||
sbss = .;
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
||||
#[macro_use]
|
||||
mod console;
|
||||
mod lang_items;
|
||||
|
@ -38,6 +41,8 @@ pub fn rust_main() -> ! {
|
|||
clear_bss();
|
||||
println!("[kernel] Hello, world!");
|
||||
mm::init();
|
||||
println!("[kernel] back to world!");
|
||||
mm::remap_test();
|
||||
loop {}
|
||||
trap::init();
|
||||
loader::load_apps();
|
||||
|
|
|
@ -1,20 +1,46 @@
|
|||
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
|
||||
use super::PageTableEntry;
|
||||
use core::fmt::{self, Debug, Formatter};
|
||||
|
||||
/// Definitions
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct PhysAddr(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct VirtAddr(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct PhysPageNum(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct VirtPageNum(pub usize);
|
||||
|
||||
/// Debugging
|
||||
|
||||
impl Debug for VirtAddr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("VA:{:#x}", self.0))
|
||||
}
|
||||
}
|
||||
impl Debug for VirtPageNum {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("VPN:{:#x}", self.0))
|
||||
}
|
||||
}
|
||||
impl Debug for PhysAddr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("PA:{:#x}", self.0))
|
||||
}
|
||||
}
|
||||
impl Debug for PhysPageNum {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("PPN:{:#x}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// T: {PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}
|
||||
/// T -> usize: T.0
|
||||
/// usize -> T: usize.into()
|
||||
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
|
||||
|
||||
/// Definitions
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PhysAddr(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VirtAddr(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PhysPageNum(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct VirtPageNum(pub usize);
|
||||
|
||||
impl From<usize> for PhysAddr {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
|
@ -22,24 +48,25 @@ impl From<usize> for PhysAddr {
|
|||
impl From<usize> for PhysPageNum {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
}
|
||||
impl From<usize> for VirtAddr {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
}
|
||||
impl From<usize> for VirtPageNum {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
}
|
||||
impl From<PhysAddr> for usize {
|
||||
fn from(v: PhysAddr) -> Self { v.0 }
|
||||
}
|
||||
impl From<PhysPageNum> for usize {
|
||||
fn from(v: PhysPageNum) -> Self { v.0 }
|
||||
}
|
||||
impl From<usize> for VirtAddr {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
}
|
||||
impl From<usize> for VirtPageNum {
|
||||
fn from(v: usize) -> Self { Self(v) }
|
||||
}
|
||||
impl From<VirtAddr> for usize {
|
||||
fn from(v: VirtAddr) -> Self { v.0 }
|
||||
}
|
||||
impl From<VirtPageNum> for usize {
|
||||
fn from(v: VirtPageNum) -> Self { v.0 }
|
||||
}
|
||||
|
||||
impl VirtAddr {
|
||||
pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) }
|
||||
pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) }
|
||||
|
@ -68,3 +95,92 @@ impl From<PhysAddr> for PhysPageNum {
|
|||
impl From<PhysPageNum> for PhysAddr {
|
||||
fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) }
|
||||
}
|
||||
|
||||
impl VirtPageNum {
|
||||
pub fn indexes(&self) -> [usize; 3] {
|
||||
let mut vpn = self.0;
|
||||
let mut idx = [0usize; 3];
|
||||
for i in (0..3).rev() {
|
||||
idx[i] = vpn & 511;
|
||||
vpn >>= 9;
|
||||
}
|
||||
idx
|
||||
}
|
||||
}
|
||||
|
||||
impl PhysPageNum {
|
||||
pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
|
||||
let pa: PhysAddr = self.clone().into();
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512)
|
||||
}
|
||||
}
|
||||
pub fn get_bytes_array(&self) -> &'static mut [u8] {
|
||||
let pa: PhysAddr = self.clone().into();
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096)
|
||||
}
|
||||
}
|
||||
pub fn get_mut<T>(&self) -> &'static mut T {
|
||||
let pa: PhysAddr = self.clone().into();
|
||||
unsafe {
|
||||
(pa.0 as *mut T).as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StepByOne {
|
||||
fn step(&mut self);
|
||||
}
|
||||
impl StepByOne for VirtPageNum {
|
||||
fn step(&mut self) {
|
||||
self.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SimpleRange<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
l: T,
|
||||
r: T,
|
||||
}
|
||||
impl<T> SimpleRange<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
pub fn new(start: T, end: T) -> Self {
|
||||
assert!(start <= end, "start {:?} > end {:?}!", start, end);
|
||||
Self { l: start, r: end }
|
||||
}
|
||||
}
|
||||
impl<T> IntoIterator for SimpleRange<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
type Item = T;
|
||||
type IntoIter = SimpleRangeIterator<T>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
SimpleRangeIterator::new(self.l, self.r)
|
||||
}
|
||||
}
|
||||
pub struct SimpleRangeIterator<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
current: T,
|
||||
end: T,
|
||||
}
|
||||
impl<T> SimpleRangeIterator<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
pub fn new(l: T, r: T) -> Self {
|
||||
Self { current: l, end: r, }
|
||||
}
|
||||
}
|
||||
impl<T> Iterator for SimpleRangeIterator<T> where
|
||||
T: StepByOne + Copy + PartialEq + PartialOrd + Debug, {
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current == self.end {
|
||||
None
|
||||
} else {
|
||||
let t = self.current;
|
||||
self.current.step();
|
||||
Some(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type VPNRange = SimpleRange<VirtPageNum>;
|
|
@ -4,17 +4,34 @@ use spin::Mutex;
|
|||
use crate::config::MEMORY_END;
|
||||
use lazy_static::*;
|
||||
use core::fmt::{self, Debug, Formatter};
|
||||
pub struct FrameTracker(PhysPageNum);
|
||||
|
||||
pub struct FrameTracker {
|
||||
pub ppn: PhysPageNum,
|
||||
}
|
||||
|
||||
impl FrameTracker {
|
||||
pub fn new(ppn: PhysPageNum) -> Self {
|
||||
//println!("into FrameTracker::new, ppn = {:?}", ppn);
|
||||
// page cleaning
|
||||
let bytes_array = ppn.get_bytes_array();
|
||||
//println!("ptr = {:p}, len = {}", bytes_array.as_ptr(), bytes_array.len());
|
||||
for i in bytes_array {
|
||||
*i = 0;
|
||||
}
|
||||
//println!("OK");
|
||||
Self { ppn }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FrameTracker {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("FrameTracker:PPN={:#x}", self.0.0))
|
||||
f.write_fmt(format_args!("FrameTracker:PPN={:#x}", self.ppn.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FrameTracker {
|
||||
fn drop(&mut self) {
|
||||
frame_dealloc(self.0);
|
||||
frame_dealloc(self.ppn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,9 +62,12 @@ impl FrameAllocator for StackFrameAllocator {
|
|||
}
|
||||
}
|
||||
fn alloc(&mut self) -> Option<PhysPageNum> {
|
||||
//println!("into StackFrameAllocator::alloc()");
|
||||
if let Some(ppn) = self.recycled.pop() {
|
||||
//println!("has recycled!");
|
||||
Some(ppn.into())
|
||||
} else {
|
||||
//println!("run out recycled, current = {}, end = {}!", self.current, self.end);
|
||||
if self.current == self.end {
|
||||
None
|
||||
} else {
|
||||
|
@ -87,10 +107,11 @@ pub fn init_frame_allocator() {
|
|||
}
|
||||
|
||||
pub fn frame_alloc() -> Option<FrameTracker> {
|
||||
//println!("into frame_alloc()");
|
||||
FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.alloc()
|
||||
.map(|ppn| FrameTracker(ppn))
|
||||
.map(|ppn| FrameTracker::new(ppn))
|
||||
}
|
||||
|
||||
fn frame_dealloc(ppn: PhysPageNum) {
|
||||
|
|
199
os/src/mm/memory_set.rs
Normal file
199
os/src/mm/memory_set.rs
Normal file
|
@ -0,0 +1,199 @@
|
|||
use super::{
|
||||
PageTable,
|
||||
PTEFlags,
|
||||
VirtAddr,
|
||||
VirtPageNum,
|
||||
PhysAddr,
|
||||
PhysPageNum,
|
||||
FrameTracker,
|
||||
VPNRange,
|
||||
frame_alloc,
|
||||
};
|
||||
use core::ops::Range;
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::vec::Vec;
|
||||
use riscv::register::satp;
|
||||
use alloc::sync::Arc;
|
||||
use lazy_static::*;
|
||||
use spin::Mutex;
|
||||
use crate::config::MEMORY_END;
|
||||
|
||||
extern "C" {
|
||||
fn stext();
|
||||
fn etext();
|
||||
fn srodata();
|
||||
fn erodata();
|
||||
fn sdata();
|
||||
fn edata();
|
||||
fn sbss_with_stack();
|
||||
fn ebss();
|
||||
fn ekernel();
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref KERNEL_SPACE: Arc<Mutex<MemorySet>> = Arc::new(Mutex::new(
|
||||
MemorySet::new_kernel()
|
||||
));
|
||||
}
|
||||
|
||||
pub struct MemorySet {
|
||||
page_table: PageTable,
|
||||
areas: Vec<MapArea>,
|
||||
}
|
||||
|
||||
impl MemorySet {
|
||||
pub fn new_bare() -> Self {
|
||||
Self {
|
||||
page_table: PageTable::new(),
|
||||
areas: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn push(&mut self, mut map_area: MapArea) {
|
||||
map_area.map(&mut self.page_table);
|
||||
self.areas.push(map_area);
|
||||
}
|
||||
pub fn new_kernel() -> Self {
|
||||
let mut memory_set = Self::new_bare();
|
||||
println!(".text [{:#x}, {:#x})", stext as usize, etext as usize);
|
||||
println!(".rodata [{:#x}, {:#x})", srodata as usize, erodata as usize);
|
||||
println!(".data [{:#x}, {:#x})", sdata as usize, edata as usize);
|
||||
println!(".bss [{:#x}, {:#x})", sbss_with_stack as usize, ebss as usize);
|
||||
println!("mapping .text section");
|
||||
memory_set.push(MapArea::new(
|
||||
(stext as usize).into(),
|
||||
(etext as usize).into(),
|
||||
MapType::Identical,
|
||||
MapPermission::R | MapPermission::X,
|
||||
));
|
||||
println!("mapping .rodata section");
|
||||
memory_set.push(MapArea::new(
|
||||
(srodata as usize).into(),
|
||||
(erodata as usize).into(),
|
||||
MapType::Identical,
|
||||
MapPermission::R,
|
||||
));
|
||||
println!("mapping .data section");
|
||||
memory_set.push(MapArea::new(
|
||||
(sdata as usize).into(),
|
||||
(edata as usize).into(),
|
||||
MapType::Identical,
|
||||
MapPermission::R | MapPermission::W,
|
||||
));
|
||||
println!("mapping .bss section");
|
||||
memory_set.push(MapArea::new(
|
||||
(sbss_with_stack as usize).into(),
|
||||
(ebss as usize).into(),
|
||||
MapType::Identical,
|
||||
MapPermission::R | MapPermission::W,
|
||||
));
|
||||
println!("mapping physical memory");
|
||||
memory_set.push(MapArea::new(
|
||||
(ekernel as usize).into(),
|
||||
MEMORY_END.into(),
|
||||
MapType::Identical,
|
||||
MapPermission::R | MapPermission::W,
|
||||
));
|
||||
memory_set
|
||||
}
|
||||
pub fn activate(&self) {
|
||||
let satp = self.page_table.token();
|
||||
unsafe {
|
||||
satp::write(satp);
|
||||
llvm_asm!("sfence.vma" :::: "volatile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapArea {
|
||||
vpn_range: VPNRange,
|
||||
data_frames: BTreeMap<VirtPageNum, FrameTracker>,
|
||||
map_type: MapType,
|
||||
map_perm: MapPermission,
|
||||
}
|
||||
|
||||
impl MapArea {
|
||||
pub fn new(
|
||||
start_va: VirtAddr,
|
||||
end_va: VirtAddr,
|
||||
map_type: MapType,
|
||||
map_perm: MapPermission
|
||||
) -> Self {
|
||||
// alignment assertion, limit to kernel remapping
|
||||
let start_vpn: VirtPageNum = start_va.into();
|
||||
let end_vpn: VirtPageNum = end_va.into();
|
||||
Self {
|
||||
vpn_range: VPNRange::new(start_vpn, end_vpn),
|
||||
data_frames: BTreeMap::new(),
|
||||
map_type,
|
||||
map_perm,
|
||||
}
|
||||
}
|
||||
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
||||
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
|
||||
let mut ppn = PhysPageNum(0);
|
||||
match self.map_type {
|
||||
MapType::Identical => {
|
||||
ppn = PhysPageNum(vpn.0);
|
||||
}
|
||||
MapType::Framed => {
|
||||
let frame = frame_alloc().unwrap();
|
||||
ppn = frame.ppn;
|
||||
self.data_frames.insert(vpn, frame);
|
||||
}
|
||||
}
|
||||
page_table.map(vpn, ppn, pte_flags);
|
||||
}
|
||||
pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
||||
match self.map_type {
|
||||
MapType::Framed => {
|
||||
self.data_frames.remove(&vpn);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
page_table.unmap(vpn);
|
||||
}
|
||||
pub fn map(&mut self, page_table: &mut PageTable) {
|
||||
for vpn in self.vpn_range {
|
||||
self.map_one(page_table, vpn);
|
||||
}
|
||||
}
|
||||
pub fn unmap(&mut self, page_table: &mut PageTable) {
|
||||
for vpn in self.vpn_range {
|
||||
self.unmap_one(page_table, vpn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MapType {
|
||||
Identical,
|
||||
Framed,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct MapPermission: u8 {
|
||||
const R = 1 << 1;
|
||||
const W = 1 << 2;
|
||||
const X = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn remap_test() {
|
||||
let mut kernel_space = KERNEL_SPACE.lock();
|
||||
let mid_text: VirtAddr = ((stext as usize + etext as usize) / 2).into();
|
||||
let mid_rodata: VirtAddr = ((srodata as usize + erodata as usize) / 2).into();
|
||||
let mid_data: VirtAddr = ((sdata as usize + edata as usize) / 2).into();
|
||||
assert_eq!(
|
||||
kernel_space.page_table.translate(mid_text.floor()).unwrap().writable(),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
kernel_space.page_table.translate(mid_rodata.floor()).unwrap().writable(),
|
||||
false,
|
||||
);
|
||||
assert_eq!(
|
||||
kernel_space.page_table.translate(mid_data.floor()).unwrap().executable(),
|
||||
false,
|
||||
);
|
||||
println!("remap_test passed!");
|
||||
}
|
|
@ -1,11 +1,19 @@
|
|||
mod heap_allocator;
|
||||
mod address;
|
||||
mod frame_allocator;
|
||||
mod page_table;
|
||||
mod memory_set;
|
||||
|
||||
use page_table::{PageTable, PTEFlags};
|
||||
use address::VPNRange;
|
||||
pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
|
||||
pub use frame_allocator::{FrameTracker, frame_alloc};
|
||||
pub use page_table::{PageTableEntry};
|
||||
pub use memory_set::{MemorySet, KERNEL_SPACE};
|
||||
pub use memory_set::remap_test;
|
||||
|
||||
pub fn init() {
|
||||
heap_allocator::init_heap();
|
||||
frame_allocator::init_frame_allocator();
|
||||
KERNEL_SPACE.clone().lock().activate();
|
||||
}
|
||||
|
|
111
os/src/mm/page_table.rs
Normal file
111
os/src/mm/page_table.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::vec;
|
||||
use bitflags::*;
|
||||
|
||||
bitflags! {
|
||||
pub struct PTEFlags: u8 {
|
||||
const V = 1 << 0;
|
||||
const R = 1 << 1;
|
||||
const W = 1 << 2;
|
||||
const X = 1 << 3;
|
||||
const U = 1 << 4;
|
||||
const G = 1 << 5;
|
||||
const A = 1 << 6;
|
||||
const D = 1 << 7;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct PageTableEntry {
|
||||
pub bits: usize,
|
||||
}
|
||||
|
||||
impl PageTableEntry {
|
||||
pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
|
||||
PageTableEntry {
|
||||
bits: ppn.0 << 10 | flags.bits as usize,
|
||||
}
|
||||
}
|
||||
pub fn empty() -> Self {
|
||||
PageTableEntry {
|
||||
bits: 0,
|
||||
}
|
||||
}
|
||||
pub fn ppn(&self) -> PhysPageNum {
|
||||
(self.bits >> 10 & ((1usize << 44) - 1)).into()
|
||||
}
|
||||
pub fn flags(&self) -> PTEFlags {
|
||||
PTEFlags::from_bits(self.bits as u8).unwrap()
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
(self.flags() & PTEFlags::V) != PTEFlags::empty()
|
||||
}
|
||||
pub fn readable(&self) -> bool {
|
||||
(self.flags() & PTEFlags::R) != PTEFlags::empty()
|
||||
}
|
||||
pub fn writable(&self) -> bool {
|
||||
(self.flags() & PTEFlags::W) != PTEFlags::empty()
|
||||
}
|
||||
pub fn executable(&self) -> bool {
|
||||
(self.flags() & PTEFlags::X) != PTEFlags::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PageTable {
|
||||
root_ppn: PhysPageNum,
|
||||
frames: Vec<FrameTracker>,
|
||||
}
|
||||
|
||||
/// Assume that it won't oom when creating/mapping.
|
||||
impl PageTable {
|
||||
pub fn new() -> Self {
|
||||
//println!("into PageTable::new()");
|
||||
let frame = frame_alloc().unwrap();
|
||||
PageTable {
|
||||
root_ppn: frame.ppn,
|
||||
frames: vec![frame],
|
||||
}
|
||||
}
|
||||
fn find_pte(&mut self, vpn: VirtPageNum, create: bool) -> Option<&mut PageTableEntry> {
|
||||
let idxs = vpn.indexes();
|
||||
let mut ppn = self.root_ppn;
|
||||
let mut result: Option<&mut PageTableEntry> = None;
|
||||
for i in 0..3 {
|
||||
let pte = &mut ppn.get_pte_array()[idxs[i]];
|
||||
if i == 2 {
|
||||
result = Some(pte);
|
||||
break;
|
||||
}
|
||||
if !pte.is_valid() {
|
||||
if !create {
|
||||
return None;
|
||||
}
|
||||
let frame = frame_alloc().unwrap();
|
||||
*pte = PageTableEntry::new(frame.ppn, PTEFlags::V);
|
||||
self.frames.push(frame);
|
||||
}
|
||||
ppn = pte.ppn();
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
|
||||
//println!("mapping {:?} {:?}", vpn, ppn);
|
||||
let pte = self.find_pte(vpn, true).unwrap();
|
||||
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
|
||||
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
|
||||
}
|
||||
pub fn unmap(&mut self, vpn: VirtPageNum) {
|
||||
let pte = self.find_pte(vpn, false).unwrap();
|
||||
assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
|
||||
*pte = PageTableEntry::empty();
|
||||
}
|
||||
pub fn translate(&mut self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
||||
self.find_pte(vpn, false)
|
||||
.map(|pte| {pte.clone()})
|
||||
}
|
||||
pub fn token(&self) -> usize {
|
||||
8usize << 60 | self.root_ppn.0
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue