Kernel remapped.
This commit is contained in:
parent
1256085d36
commit
0011fe9477
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"] }
|
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||||
buddy_system_allocator = "0.6"
|
buddy_system_allocator = "0.6"
|
||||||
spin = "0.7.0"
|
spin = "0.7.0"
|
||||||
|
bitflags = "1.2.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
board_qemu = []
|
board_qemu = []
|
||||||
|
|
|
@ -29,11 +29,9 @@ _num_app:
|
||||||
.quad {}"#, apps.len())?;
|
.quad {}"#, apps.len())?;
|
||||||
|
|
||||||
for i in 0..apps.len() {
|
for i in 0..apps.len() {
|
||||||
writeln!(f, r#"
|
writeln!(f, r#".quad app_{}_start"#, i)?;
|
||||||
.quad app_{}_start"#, i)?;
|
|
||||||
}
|
}
|
||||||
writeln!(f, r#"
|
writeln!(f, r#".quad app_{}_end"#, apps.len() - 1)?;
|
||||||
.quad app_{}_end"#, apps.len() - 1)?;
|
|
||||||
|
|
||||||
for (idx, app) in apps.iter().enumerate() {
|
for (idx, app) in apps.iter().enumerate() {
|
||||||
println!("app_{}: {}", idx, app);
|
println!("app_{}: {}", idx, app);
|
||||||
|
|
|
@ -29,6 +29,7 @@ SECTIONS
|
||||||
|
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
edata = .;
|
edata = .;
|
||||||
|
sbss_with_stack = .;
|
||||||
.bss : {
|
.bss : {
|
||||||
*(.bss.stack)
|
*(.bss.stack)
|
||||||
sbss = .;
|
sbss = .;
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod console;
|
mod console;
|
||||||
mod lang_items;
|
mod lang_items;
|
||||||
|
@ -38,6 +41,8 @@ pub fn rust_main() -> ! {
|
||||||
clear_bss();
|
clear_bss();
|
||||||
println!("[kernel] Hello, world!");
|
println!("[kernel] Hello, world!");
|
||||||
mm::init();
|
mm::init();
|
||||||
|
println!("[kernel] back to world!");
|
||||||
|
mm::remap_test();
|
||||||
loop {}
|
loop {}
|
||||||
trap::init();
|
trap::init();
|
||||||
loader::load_apps();
|
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: {PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}
|
||||||
/// T -> usize: T.0
|
/// T -> usize: T.0
|
||||||
/// usize -> T: usize.into()
|
/// 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 {
|
impl From<usize> for PhysAddr {
|
||||||
fn from(v: usize) -> Self { Self(v) }
|
fn from(v: usize) -> Self { Self(v) }
|
||||||
|
@ -22,24 +48,25 @@ impl From<usize> for PhysAddr {
|
||||||
impl From<usize> for PhysPageNum {
|
impl From<usize> for PhysPageNum {
|
||||||
fn from(v: usize) -> Self { Self(v) }
|
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 {
|
impl From<PhysAddr> for usize {
|
||||||
fn from(v: PhysAddr) -> Self { v.0 }
|
fn from(v: PhysAddr) -> Self { v.0 }
|
||||||
}
|
}
|
||||||
impl From<PhysPageNum> for usize {
|
impl From<PhysPageNum> for usize {
|
||||||
fn from(v: PhysPageNum) -> Self { v.0 }
|
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 {
|
impl From<VirtAddr> for usize {
|
||||||
fn from(v: VirtAddr) -> Self { v.0 }
|
fn from(v: VirtAddr) -> Self { v.0 }
|
||||||
}
|
}
|
||||||
impl From<VirtPageNum> for usize {
|
impl From<VirtPageNum> for usize {
|
||||||
fn from(v: VirtPageNum) -> Self { v.0 }
|
fn from(v: VirtPageNum) -> Self { v.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtAddr {
|
impl VirtAddr {
|
||||||
pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) }
|
pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) }
|
||||||
pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 + PAGE_SIZE - 1) / 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 {
|
impl From<PhysPageNum> for PhysAddr {
|
||||||
fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) }
|
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 crate::config::MEMORY_END;
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
use core::fmt::{self, Debug, Formatter};
|
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 {
|
impl Debug for FrameTracker {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
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 {
|
impl Drop for FrameTracker {
|
||||||
fn drop(&mut self) {
|
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> {
|
fn alloc(&mut self) -> Option<PhysPageNum> {
|
||||||
|
//println!("into StackFrameAllocator::alloc()");
|
||||||
if let Some(ppn) = self.recycled.pop() {
|
if let Some(ppn) = self.recycled.pop() {
|
||||||
|
//println!("has recycled!");
|
||||||
Some(ppn.into())
|
Some(ppn.into())
|
||||||
} else {
|
} else {
|
||||||
|
//println!("run out recycled, current = {}, end = {}!", self.current, self.end);
|
||||||
if self.current == self.end {
|
if self.current == self.end {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,10 +107,11 @@ pub fn init_frame_allocator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_alloc() -> Option<FrameTracker> {
|
pub fn frame_alloc() -> Option<FrameTracker> {
|
||||||
|
//println!("into frame_alloc()");
|
||||||
FRAME_ALLOCATOR
|
FRAME_ALLOCATOR
|
||||||
.lock()
|
.lock()
|
||||||
.alloc()
|
.alloc()
|
||||||
.map(|ppn| FrameTracker(ppn))
|
.map(|ppn| FrameTracker::new(ppn))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_dealloc(ppn: PhysPageNum) {
|
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 heap_allocator;
|
||||||
mod address;
|
mod address;
|
||||||
mod frame_allocator;
|
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 address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
|
||||||
pub use frame_allocator::{FrameTracker, frame_alloc};
|
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() {
|
pub fn init() {
|
||||||
heap_allocator::init_heap();
|
heap_allocator::init_heap();
|
||||||
frame_allocator::init_frame_allocator();
|
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