|
|
@ -5,8 +5,9 @@ use core::arch::asm;
|
|
|
|
use bitflags::bitflags;
|
|
|
|
use bitflags::bitflags;
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use riscv::register::satp;
|
|
|
|
use riscv::register::satp;
|
|
|
|
|
|
|
|
use xmas_elf;
|
|
|
|
use crate::sync::UPSafeCell;
|
|
|
|
use crate::sync::UPSafeCell;
|
|
|
|
use crate::config::{MEMORY_END, PAGE_SIZE, TRAMPOLINE};
|
|
|
|
use crate::config::{MEMORY_END, PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, USER_STACK_SIZE};
|
|
|
|
use crate::mm::address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum, VPNRange};
|
|
|
|
use crate::mm::address::{PhysAddr, PhysPageNum, VirtAddr, VirtPageNum, VPNRange};
|
|
|
|
use crate::mm::frame_allocator::{frame_alloc, FrameTracker};
|
|
|
|
use crate::mm::frame_allocator::{frame_alloc, FrameTracker};
|
|
|
|
use crate::mm::page_table::{PageTable, PTEFlags};
|
|
|
|
use crate::mm::page_table::{PageTable, PTEFlags};
|
|
|
@ -65,7 +66,7 @@ impl MapArea {
|
|
|
|
// 截取抛弃内存碎片
|
|
|
|
// 截取抛弃内存碎片
|
|
|
|
let start_vpn: VirtPageNum = start_va.floor();
|
|
|
|
let start_vpn: VirtPageNum = start_va.floor();
|
|
|
|
let end_vpn: VirtPageNum = end_va.ceil();
|
|
|
|
let end_vpn: VirtPageNum = end_va.ceil();
|
|
|
|
|
|
|
|
println!("start va: {} start vpn {}", start_va.0, start_vpn.0);
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
|
vpn_range: VPNRange {l:start_vpn, r: end_vpn},
|
|
|
|
vpn_range: VPNRange {l:start_vpn, r: end_vpn},
|
|
|
|
data_frames: BTreeMap::new(),
|
|
|
|
data_frames: BTreeMap::new(),
|
|
|
@ -110,7 +111,9 @@ impl MapArea {
|
|
|
|
|
|
|
|
|
|
|
|
// 映射 当前逻辑段中的每一个虚拟页, 到页表中
|
|
|
|
// 映射 当前逻辑段中的每一个虚拟页, 到页表中
|
|
|
|
pub fn map(&mut self, page_table: &mut PageTable) {
|
|
|
|
pub fn map(&mut self, page_table: &mut PageTable) {
|
|
|
|
|
|
|
|
println!("self.vpn_range.get_start {} {}", self.vpn_range.l.0, self.vpn_range.r.0);
|
|
|
|
for vpn in self.vpn_range {
|
|
|
|
for vpn in self.vpn_range {
|
|
|
|
|
|
|
|
println!("range vpn :{}", vpn.0);
|
|
|
|
self.map_one(page_table, vpn);
|
|
|
|
self.map_one(page_table, vpn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -155,8 +158,8 @@ impl MapArea {
|
|
|
|
|
|
|
|
|
|
|
|
// 表示一个地址空间, 它是一个页表和 包含所有段信息的页表组成
|
|
|
|
// 表示一个地址空间, 它是一个页表和 包含所有段信息的页表组成
|
|
|
|
pub struct MemorySet {
|
|
|
|
pub struct MemorySet {
|
|
|
|
page_table: PageTable,
|
|
|
|
pub page_table: PageTable,
|
|
|
|
areas: Vec<MapArea>,
|
|
|
|
pub areas: Vec<MapArea>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MemorySet {
|
|
|
|
impl MemorySet {
|
|
|
@ -166,6 +169,114 @@ impl MemorySet {
|
|
|
|
areas: Vec::new(),
|
|
|
|
areas: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) {
|
|
|
|
|
|
|
|
let mut memory_set = Self::new();
|
|
|
|
|
|
|
|
// map trampoline
|
|
|
|
|
|
|
|
// 创建一个地址空间
|
|
|
|
|
|
|
|
memory_set.map_trampoline();
|
|
|
|
|
|
|
|
// map program headers of elf, with U flag
|
|
|
|
|
|
|
|
// 分析外部传进来的 elf文件数据
|
|
|
|
|
|
|
|
println!("enf len: {}", elf_data.len());
|
|
|
|
|
|
|
|
let elf = xmas_elf::ElfFile::new(elf_data).unwrap();
|
|
|
|
|
|
|
|
let elf_header = elf.header;
|
|
|
|
|
|
|
|
let magic = elf_header.pt1.magic;
|
|
|
|
|
|
|
|
assert_eq!(magic, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
|
|
|
|
|
|
|
|
let ph_count = elf_header.pt2.ph_count();
|
|
|
|
|
|
|
|
// 得到所有的段数量
|
|
|
|
|
|
|
|
let mut max_end_vpn = VirtPageNum(0);
|
|
|
|
|
|
|
|
// 循环所有的段
|
|
|
|
|
|
|
|
for i in 0..ph_count {
|
|
|
|
|
|
|
|
// 得到当前段
|
|
|
|
|
|
|
|
let ph = elf.program_header(i).unwrap();
|
|
|
|
|
|
|
|
// 确定有加载的必要
|
|
|
|
|
|
|
|
if ph.get_type().unwrap() == xmas_elf::program::Type::Load {
|
|
|
|
|
|
|
|
// 当前段开始位置
|
|
|
|
|
|
|
|
let start_va: VirtAddr = (ph.virtual_addr() as usize).into();
|
|
|
|
|
|
|
|
// 当前段结束位置 (开始位置+大小)
|
|
|
|
|
|
|
|
let end_va: VirtAddr = ((ph.virtual_addr() + ph.mem_size()) as usize).into();
|
|
|
|
|
|
|
|
println!("start_va {} end_va {}", start_va.0, end_va.0);
|
|
|
|
|
|
|
|
// 当前段权限
|
|
|
|
|
|
|
|
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::from(start_va, end_va, MapType::Framed, map_perm);
|
|
|
|
|
|
|
|
// 每次都更新最后的逻辑段的最后结束最大的逻辑地址
|
|
|
|
|
|
|
|
max_end_vpn = map_area.vpn_range.r;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 当前逻辑段, 添加到地址空间, 并copy数据进去
|
|
|
|
|
|
|
|
memory_set.push(
|
|
|
|
|
|
|
|
map_area,
|
|
|
|
|
|
|
|
Some(&elf.input[ph.offset() as usize..(ph.offset() + ph.file_size()) as usize]),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// map user stack with U flags
|
|
|
|
|
|
|
|
// 将最后一个最大的逻辑段的结束的页, 转为逻辑地址 左移12位 得到39位的VirtAddr
|
|
|
|
|
|
|
|
let max_end_va: VirtAddr = max_end_vpn.into();
|
|
|
|
|
|
|
|
// 根据riscv 的规则, 转成一个 合法的地址 (todo 为什么这里需要转成合法的地址:将高位全部设置为1, 上面的start_va 不转就传?, 而且不直接可以使用end_va 吗? 这里还创建一个max_end_vpn?)
|
|
|
|
|
|
|
|
let mut user_stack_bottom: usize = max_end_va.into();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// guard page 放置 一页 保护页隔离用户栈
|
|
|
|
|
|
|
|
user_stack_bottom += PAGE_SIZE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 保护页之后 再增加 用户栈大小,得到栈底和当前的栈顶
|
|
|
|
|
|
|
|
// 此时 user_stack_top 距离 max_end_vpn 三个页
|
|
|
|
|
|
|
|
let user_stack_top = user_stack_bottom + USER_STACK_SIZE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 添加 用户逻辑栈段并映射物理地址页, 到当前的地址空间
|
|
|
|
|
|
|
|
memory_set.push(
|
|
|
|
|
|
|
|
MapArea::from(
|
|
|
|
|
|
|
|
user_stack_bottom.into(),
|
|
|
|
|
|
|
|
user_stack_top.into(),
|
|
|
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
|
|
|
MapPermission::R | MapPermission::W | MapPermission::U,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// used in sbrk
|
|
|
|
|
|
|
|
memory_set.push(
|
|
|
|
|
|
|
|
MapArea::from(
|
|
|
|
|
|
|
|
user_stack_top.into(),
|
|
|
|
|
|
|
|
user_stack_top.into(),
|
|
|
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
|
|
|
MapPermission::R | MapPermission::W | MapPermission::U,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置 TrapContext为统一的虚拟地址
|
|
|
|
|
|
|
|
// 将 虚拟地址的 次高页添加到用户空间, 后面会被内核强行找到物理地址并修改为 trap context
|
|
|
|
|
|
|
|
println!("TRAP_CONTEXT: {}, TRAMPOLINE: {}", TRAP_CONTEXT, TRAMPOLINE);
|
|
|
|
|
|
|
|
memory_set.push(
|
|
|
|
|
|
|
|
MapArea::from(
|
|
|
|
|
|
|
|
TRAP_CONTEXT.into(),
|
|
|
|
|
|
|
|
TRAMPOLINE.into(),
|
|
|
|
|
|
|
|
MapType::Framed,
|
|
|
|
|
|
|
|
MapPermission::R | MapPermission::W,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
None,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
println!(3);
|
|
|
|
|
|
|
|
(
|
|
|
|
|
|
|
|
memory_set, // 地址空间
|
|
|
|
|
|
|
|
user_stack_top, // 用户栈底和当前的栈顶, 他在地址空间各个逻辑段的上面, 同时
|
|
|
|
|
|
|
|
elf.header.pt2.entry_point() as usize, // elf文件的入口地址
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl MemorySet {
|
|
|
|
impl MemorySet {
|
|
|
|