|
|
|
@ -1,22 +1,15 @@
|
|
|
|
|
use super::{PageTable, PageTableEntry, PTEFlags};
|
|
|
|
|
use super::{VirtPageNum, VirtAddr, PhysPageNum, PhysAddr};
|
|
|
|
|
use super::{FrameTracker, frame_alloc};
|
|
|
|
|
use super::{VPNRange, StepByOne};
|
|
|
|
|
use super::{frame_alloc, FrameTracker};
|
|
|
|
|
use super::{PTEFlags, PageTable, PageTableEntry};
|
|
|
|
|
use super::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum};
|
|
|
|
|
use super::{StepByOne, VPNRange};
|
|
|
|
|
use crate::config::{MEMORY_END, MMIO, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE};
|
|
|
|
|
use crate::sync::UPSafeCell;
|
|
|
|
|
use alloc::collections::BTreeMap;
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
use riscv::register::satp;
|
|
|
|
|
use alloc::sync::Arc;
|
|
|
|
|
use lazy_static::*;
|
|
|
|
|
use crate::sync::UPSafeCell;
|
|
|
|
|
use crate::config::{
|
|
|
|
|
MEMORY_END,
|
|
|
|
|
PAGE_SIZE,
|
|
|
|
|
TRAMPOLINE,
|
|
|
|
|
TRAP_CONTEXT,
|
|
|
|
|
USER_STACK_SIZE,
|
|
|
|
|
MMIO,
|
|
|
|
|
};
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
use core::arch::asm;
|
|
|
|
|
use lazy_static::*;
|
|
|
|
|
use riscv::register::satp;
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
fn stext();
|
|
|
|
@ -32,9 +25,8 @@ extern "C" {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
|
pub static ref KERNEL_SPACE: Arc<UPSafeCell<MemorySet>> = Arc::new(unsafe {
|
|
|
|
|
UPSafeCell::new(MemorySet::new_kernel())
|
|
|
|
|
});
|
|
|
|
|
pub static ref KERNEL_SPACE: Arc<UPSafeCell<MemorySet>> =
|
|
|
|
|
Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn kernel_token() -> usize {
|
|
|
|
@ -57,17 +49,24 @@ impl MemorySet {
|
|
|
|
|
self.page_table.token()
|
|
|
|
|
}
|
|
|
|
|
/// Assume that no conflicts.
|
|
|
|
|
pub fn insert_framed_area(&mut self, start_va: VirtAddr, end_va: VirtAddr, permission: MapPermission) {
|
|
|
|
|
self.push(MapArea::new(
|
|
|
|
|
start_va,
|
|
|
|
|
end_va,
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
permission,
|
|
|
|
|
), None);
|
|
|
|
|
pub fn insert_framed_area(
|
|
|
|
|
&mut self,
|
|
|
|
|
start_va: VirtAddr,
|
|
|
|
|
end_va: VirtAddr,
|
|
|
|
|
permission: MapPermission,
|
|
|
|
|
) {
|
|
|
|
|
self.push(
|
|
|
|
|
MapArea::new(start_va, end_va, MapType::Framed, permission),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) {
|
|
|
|
|
if let Some((idx, area)) = self.areas.iter_mut().enumerate()
|
|
|
|
|
.find(|(_, area)| area.vpn_range.get_start() == start_vpn) {
|
|
|
|
|
if let Some((idx, area)) = self
|
|
|
|
|
.areas
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.find(|(_, area)| area.vpn_range.get_start() == start_vpn)
|
|
|
|
|
{
|
|
|
|
|
area.unmap(&mut self.page_table);
|
|
|
|
|
self.areas.remove(idx);
|
|
|
|
|
}
|
|
|
|
@ -96,50 +95,71 @@ impl MemorySet {
|
|
|
|
|
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!(
|
|
|
|
|
".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,
|
|
|
|
|
), None);
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(stext as usize).into(),
|
|
|
|
|
(etext as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::X,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
println!("mapping .rodata section");
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
(srodata as usize).into(),
|
|
|
|
|
(erodata as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R,
|
|
|
|
|
), None);
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(srodata as usize).into(),
|
|
|
|
|
(erodata as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
println!("mapping .data section");
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
(sdata as usize).into(),
|
|
|
|
|
(edata as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
), None);
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(sdata as usize).into(),
|
|
|
|
|
(edata as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
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,
|
|
|
|
|
), None);
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(sbss_with_stack as usize).into(),
|
|
|
|
|
(ebss as usize).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
println!("mapping physical memory");
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
(ekernel as usize).into(),
|
|
|
|
|
MEMORY_END.into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
), None);
|
|
|
|
|
println!("mapping memory-mapped registers");
|
|
|
|
|
for pair in MMIO {
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
(*pair).0.into(),
|
|
|
|
|
((*pair).0 + (*pair).1).into(),
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(ekernel as usize).into(),
|
|
|
|
|
MEMORY_END.into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
), None);
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
println!("mapping memory-mapped registers");
|
|
|
|
|
for pair in MMIO {
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
(*pair).0.into(),
|
|
|
|
|
((*pair).0 + (*pair).1).into(),
|
|
|
|
|
MapType::Identical,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
memory_set
|
|
|
|
|
}
|
|
|
|
@ -163,19 +183,20 @@ impl MemorySet {
|
|
|
|
|
let end_va: VirtAddr = ((ph.virtual_addr() + ph.mem_size()) as usize).into();
|
|
|
|
|
let mut map_perm = MapPermission::U;
|
|
|
|
|
let ph_flags = ph.flags();
|
|
|
|
|
if ph_flags.is_read() { map_perm |= MapPermission::R; }
|
|
|
|
|
if ph_flags.is_write() { map_perm |= MapPermission::W; }
|
|
|
|
|
if ph_flags.is_execute() { map_perm |= MapPermission::X; }
|
|
|
|
|
let map_area = MapArea::new(
|
|
|
|
|
start_va,
|
|
|
|
|
end_va,
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
map_perm,
|
|
|
|
|
);
|
|
|
|
|
if ph_flags.is_read() {
|
|
|
|
|
map_perm |= MapPermission::R;
|
|
|
|
|
}
|
|
|
|
|
if ph_flags.is_write() {
|
|
|
|
|
map_perm |= MapPermission::W;
|
|
|
|
|
}
|
|
|
|
|
if ph_flags.is_execute() {
|
|
|
|
|
map_perm |= MapPermission::X;
|
|
|
|
|
}
|
|
|
|
|
let map_area = MapArea::new(start_va, end_va, MapType::Framed, map_perm);
|
|
|
|
|
max_end_vpn = map_area.vpn_range.get_end();
|
|
|
|
|
memory_set.push(
|
|
|
|
|
map_area,
|
|
|
|
|
Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize])
|
|
|
|
|
Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -185,20 +206,30 @@ impl MemorySet {
|
|
|
|
|
// guard page
|
|
|
|
|
user_stack_bottom += PAGE_SIZE;
|
|
|
|
|
let user_stack_top = user_stack_bottom + USER_STACK_SIZE;
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
user_stack_bottom.into(),
|
|
|
|
|
user_stack_top.into(),
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
MapPermission::R | MapPermission::W | MapPermission::U,
|
|
|
|
|
), None);
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
user_stack_bottom.into(),
|
|
|
|
|
user_stack_top.into(),
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
MapPermission::R | MapPermission::W | MapPermission::U,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
// map TrapContext
|
|
|
|
|
memory_set.push(MapArea::new(
|
|
|
|
|
TRAP_CONTEXT.into(),
|
|
|
|
|
TRAMPOLINE.into(),
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
), None);
|
|
|
|
|
(memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
|
|
|
|
|
memory_set.push(
|
|
|
|
|
MapArea::new(
|
|
|
|
|
TRAP_CONTEXT.into(),
|
|
|
|
|
TRAMPOLINE.into(),
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
(
|
|
|
|
|
memory_set,
|
|
|
|
|
user_stack_top,
|
|
|
|
|
elf.header.pt2.entry_point() as usize,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
|
|
|
|
|
let mut memory_set = Self::new_bare();
|
|
|
|
@ -212,7 +243,9 @@ impl MemorySet {
|
|
|
|
|
for vpn in area.vpn_range {
|
|
|
|
|
let src_ppn = user_space.translate(vpn).unwrap().ppn();
|
|
|
|
|
let dst_ppn = memory_set.translate(vpn).unwrap().ppn();
|
|
|
|
|
dst_ppn.get_bytes_array().copy_from_slice(src_ppn.get_bytes_array());
|
|
|
|
|
dst_ppn
|
|
|
|
|
.get_bytes_array()
|
|
|
|
|
.copy_from_slice(src_ppn.get_bytes_array());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memory_set
|
|
|
|
@ -245,7 +278,7 @@ impl MapArea {
|
|
|
|
|
start_va: VirtAddr,
|
|
|
|
|
end_va: VirtAddr,
|
|
|
|
|
map_type: MapType,
|
|
|
|
|
map_perm: MapPermission
|
|
|
|
|
map_perm: MapPermission,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let start_vpn: VirtPageNum = start_va.floor();
|
|
|
|
|
let end_vpn: VirtPageNum = end_va.ceil();
|
|
|
|
@ -344,15 +377,27 @@ pub fn remap_test() {
|
|
|
|
|
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(),
|
|
|
|
|
kernel_space
|
|
|
|
|
.page_table
|
|
|
|
|
.translate(mid_text.floor())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.writable(),
|
|
|
|
|
false
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
kernel_space.page_table.translate(mid_rodata.floor()).unwrap().writable(),
|
|
|
|
|
kernel_space
|
|
|
|
|
.page_table
|
|
|
|
|
.translate(mid_rodata.floor())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.writable(),
|
|
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
kernel_space.page_table.translate(mid_data.floor()).unwrap().executable(),
|
|
|
|
|
kernel_space
|
|
|
|
|
.page_table
|
|
|
|
|
.translate(mid_data.floor())
|
|
|
|
|
.unwrap()
|
|
|
|
|
.executable(),
|
|
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
println!("remap_test passed!");
|
|
|
|
|