Skip to content

Commit

Permalink
ch4 finish
Browse files Browse the repository at this point in the history
  • Loading branch information
GYHPCG committed Nov 2, 2023
1 parent 486abc3 commit e8f87cf
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 73 deletions.
2 changes: 2 additions & 0 deletions os/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub fn get_num_app() -> usize {
}

/// get applications data
/// task可以通过虚拟页来访问对应的内容,因此只需要
/// 在载入的时候将存放程序的位置作为参数建立task的地址空间就可以了
pub fn get_app_data(app_id: usize) -> &'static [u8] {
extern "C" {
fn _num_app();
Expand Down
9 changes: 8 additions & 1 deletion os/src/mm/address.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Implementation of physical and virtual address and page number.
//!建立页与地址之间的转换关系
use super::PageTableEntry;
use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS};
use core::fmt::{self, Debug, Formatter};
Expand Down Expand Up @@ -93,6 +94,9 @@ impl From<VirtPageNum> for usize {
}
}
/// virtual address impl
/// 为各种结构构建方法,提供虚拟页与虚拟地址,物理页与物理地址间的转换方法。
/// 其中floor()返回该地址单元所在的页,
/// 若地址单元为某页的第一个单元,则ceil()返回其所在的页,否则返回下一页。
impl VirtAddr {
/// Get the (floor) virtual page number
pub fn floor(&self) -> VirtPageNum {
Expand Down Expand Up @@ -154,7 +158,7 @@ impl From<PhysPageNum> for PhysAddr {
Self(v.0 << PAGE_SIZE_BITS)
}
}

// 该函数用来把一个虚拟页号拆解成一级页号、二级页号和三级页号,返回一个三元数组
impl VirtPageNum {
/// Get the indexes of the page table entry
pub fn indexes(&self) -> [usize; 3] {
Expand All @@ -175,6 +179,8 @@ impl PhysAddr {
unsafe { (self.0 as *mut T).as_mut().unwrap() }
}
}
// 只需要查表就可以找到对应的物理页帧,当目标物理页帧存放的是页表的时候,我们希望
// 以pte指针的形式来访问它;当目标页帧存放程序数据的时候,我们则希望能够按指定的类型来访问它
impl PhysPageNum {
/// Get the reference of page table(array of ptes)
pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
Expand All @@ -194,6 +200,7 @@ impl PhysPageNum {
}

/// iterator for phy/virt page number
/// 表示连续的一段虚拟页
pub trait StepByOne {
/// step by one element(page number)
fn step(&mut self);
Expand Down
17 changes: 11 additions & 6 deletions os/src/mm/frame_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl FrameTracker {
pub fn new(ppn: PhysPageNum) -> Self {
// page cleaning
let bytes_array = ppn.get_bytes_array();
for i in bytes_array {
for i in bytes_array { // 将对应的页帧清空。
*i = 0;
}
Self { ppn }
Expand All @@ -38,19 +38,24 @@ impl Drop for FrameTracker {
frame_dealloc(self.ppn);
}
}

/// 分配空闲物理页帧与释放已用页帧
// 描述一个物理页帧管理器需要提供哪些功能:
trait FrameAllocator {
fn new() -> Self;
fn alloc(&mut self) -> Option<PhysPageNum>;
fn dealloc(&mut self, ppn: PhysPageNum);
}
/// an implementation for frame allocator
/// 栈式物理页帧管理策略

pub struct StackFrameAllocator {
current: usize,
end: usize,
recycled: Vec<usize>,
current: usize, // 空闲内存的起始物理号
end: usize, // 空闲内存的结束物理号
recycled: Vec<usize>, // 后入先出的方式保存了被回收的物理页号
}

/// [current,end)表示从未使用过的且可用的物理页帧号,recycled用来存放被回收的物理页,
/// 当需要分配新的页帧的时候,优先从recycled中获取页帧,
/// 如果recycled为空,再从[current,end)区域分配可用帧。当页帧被回收的时候,将该栈帧推入recycled中
impl StackFrameAllocator {
pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) {
self.current = l.0;
Expand Down
58 changes: 41 additions & 17 deletions os/src/mm/memory_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ extern "C" {

lazy_static! {
/// The kernel's initial memory mapping(kernel address space)
/// 实例化一个内核的地址空间:
pub static ref KERNEL_SPACE: Arc<UPSafeCell<MemorySet>> =
Arc::new(unsafe { UPSafeCell::new(MemorySet::new_kernel()) });
}
/// address space
/// 地址空间与进程是一一对应的
pub struct MemorySet {
page_table: PageTable,
areas: Vec<MapArea>,
mmap_frames: BTreeMap<VirtPageNum, FrameTracker>,
page_table: PageTable, //一个页表
areas: Vec<MapArea>, //一系列逻辑段
mmap_frames: BTreeMap<VirtPageNum, FrameTracker>, //vpn和ppn的映射
}

impl MemorySet {
Expand All @@ -50,10 +52,11 @@ impl MemorySet {
}
}
/// Get the page table token
pub fn token(&self) -> usize {
pub fn token(&self) -> usize { //获取内置页表的satp
self.page_table.token()
}
/// Assume that no conflicts.
/// MemorySet中根据参数插入一个没有存放数据的Frame类型的MapArea。
pub fn insert_framed_area(
&mut self,
start_va: VirtAddr,
Expand All @@ -65,14 +68,17 @@ impl MemorySet {
None,
);
}
//push方法将data写入map_area中,再将map_area插入MemorySet中
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
map_area.map(&mut self.page_table);
map_area.map(&mut self.page_table); //将map_area与page_table绑定并分配物理页帧
if let Some(data) = data {
map_area.copy_data(&mut self.page_table, data);
}
self.areas.push(map_area);
}
/// Mention that trampoline is not collected by areas.
/// strampoline对应了__alltraps所对应的物理页的起始地址
/// 在内置页表中将虚拟地址TRAMPOLINE所对应的虚拟页映射到__alltraps所对应的页。
fn map_trampoline(&mut self) {
self.page_table.map(
VirtAddr::from(TRAMPOLINE).into(),
Expand All @@ -81,6 +87,7 @@ impl MemorySet {
);
}
/// Without kernel stacks.
/// 内核载入时映射地址空间的函数:
pub fn new_kernel() -> Self {
let mut memory_set = Self::new_bare();
// map trampoline
Expand Down Expand Up @@ -147,6 +154,8 @@ impl MemorySet {
}
/// Include sections in elf and trampoline and TrapContext and user stack,
/// also returns user_sp_base and entry point.
/// 载入elf文件的用户态程序的地址空间建立过程:
/// 返回了一个三元组(进程的MemorySet,用户栈地址,入口地址)
pub fn from_elf(elf_data: &[u8]) -> (Self, usize, usize) {
let mut memory_set = Self::new_bare();
// map trampoline
Expand All @@ -156,6 +165,9 @@ impl MemorySet {
let elf_header = elf.header;
let magic = elf_header.pt1.magic;
assert_eq!(magic, [0x7f, 0x45, 0x4c, 0x46], "invalid elf!");
// 应用程序在链接的时候就已经确定了每个数据的虚拟地址,在载入系统的时候,数据在程序中的虚
// 拟地址和在虚拟内存中的虚拟地址是一致的,这样才能够保证程序在进入虚拟内存系
// 统后依然可以正常的运行。注意flags的设置,一定是MapPermission::U的,这样才能在用户态下执行。
let ph_count = elf_header.pt2.ph_count();
let mut max_end_vpn = VirtPageNum(0);
for i in 0..ph_count {
Expand Down Expand Up @@ -183,6 +195,8 @@ impl MemorySet {
}
}
// map user stack with U flags
// max_end_vpn是用户程序部分所占用的最后一个虚拟页,我们从它后面的一个页开始用作用户栈,
// 需要设置MapPermission::R | MapPermission::W ||MapPermission::U
let max_end_va: VirtAddr = max_end_vpn.into();
let mut user_stack_bottom: usize = max_end_va.into();
// guard page
Expand All @@ -208,6 +222,7 @@ impl MemorySet {
None,
);
// map TrapContext
// 这一步是预留了TRAMPOLINE前面的一个虚拟页来放置TRAP_CONTEXT
memory_set.push(
MapArea::new(
TRAP_CONTEXT_BASE.into(),
Expand All @@ -227,8 +242,8 @@ impl MemorySet {
pub fn activate(&self) {
let satp = self.page_table.token();
unsafe {
satp::write(satp);
asm!("sfence.vma");
satp::write(satp); //切换页表
asm!("sfence.vma"); //刷新TLB
}
}
/// Translate a virtual page number to a page table entry
Expand Down Expand Up @@ -327,15 +342,16 @@ impl MemorySet {
}
}
/// map area structure, controls a contiguous piece of virtual memory
/// 逻辑段的结构与方法
pub struct MapArea {
vpn_range: VPNRange,
data_frames: BTreeMap<VirtPageNum, FrameTracker>,
vpn_range: VPNRange, // 迭代器,元素为所有的虚拟页
data_frames: BTreeMap<VirtPageNum, FrameTracker>, //记录映射关系
map_type: MapType,
map_perm: MapPermission,
map_perm: MapPermission, // 逻辑段的访问权限
}

impl MapArea {
pub fn new(
pub fn new( //创建一个新的MapArea
start_va: VirtAddr,
end_va: VirtAddr,
map_type: MapType,
Expand All @@ -350,13 +366,15 @@ impl MapArea {
map_perm,
}
}
////为MapArea中的一个虚拟页映射物理页,若为恒等映射,则直接映射到vpn同号的ppn,否则
/// 重新分配一个物理页帧使之映射。映射完成后需要在页表中也完成映射操作。
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
let ppn: PhysPageNum;
match self.map_type {
MapType::Identical => {
MapType::Identical => { //恒等映射
ppn = PhysPageNum(vpn.0);
}
MapType::Framed => {
MapType::Framed => {
let frame = frame_alloc().unwrap();
ppn = frame.ppn;
self.data_frames.insert(vpn, frame);
Expand All @@ -365,18 +383,21 @@ impl MapArea {
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
page_table.map(vpn, ppn, pte_flags);
}
//解除映射
#[allow(unused)]
pub fn unmap_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
if self.map_type == MapType::Framed {
self.data_frames.remove(&vpn);
}
page_table.unmap(vpn);
}
//完成对MapArea中所有虚拟页的映射
pub fn map(&mut self, page_table: &mut PageTable) {
for vpn in self.vpn_range {
self.map_one(page_table, vpn);
}
}
//解除对MapArea中所有虚拟页的映射
#[allow(unused)]
pub fn unmap(&mut self, page_table: &mut PageTable) {
for vpn in self.vpn_range {
Expand All @@ -399,6 +420,9 @@ impl MapArea {
}
/// data: start-aligned but maybe with shorter length
/// assume that all frames were cleared before
/// 实现在MapArea中存入数组数据的方法:
/// 函数将数据放入范围内的每个页中,一个页存满了则进入下一个页存放,
/// 直到全部数据存放完毕或者MapArea中的虚拟页全部被用完。
pub fn copy_data(&mut self, page_table: &mut PageTable, data: &[u8]) {
assert_eq!(self.map_type, MapType::Framed);
let mut start: usize = 0;
Expand All @@ -423,14 +447,14 @@ impl MapArea {

#[derive(Copy, Clone, PartialEq, Debug)]
/// map type for memory set: identical or framed
pub enum MapType {
Identical,
Framed,
pub enum MapType {
Identical, //表示对等映射
Framed, //表示对于每个虚拟页面都需要映射到一个新分配的物理页帧
}

bitflags! {
/// map permission corresponding to that in pte: `R W X U`
pub struct MapPermission: u8 {
pub struct MapPermission: u8 { //与PTEflags是同样的结构
///Readable
const R = 1 << 1;
///Writable
Expand Down
30 changes: 15 additions & 15 deletions os/src/mm/page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ pub struct PageTableEntry {

impl PageTableEntry {
/// Create a new page table entry
pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self { //根据物理页帧号和标记位构建一个PTE
PageTableEntry {
bits: ppn.0 << 10 | flags.bits as usize,
}
}
/// Create an empty page table entry
pub fn empty() -> Self {
pub fn empty() -> Self { //创建一个空的PTE
PageTableEntry { bits: 0 }
}
/// Get the physical page number from the page table entry
pub fn ppn(&self) -> PhysPageNum {
pub fn ppn(&self) -> PhysPageNum { //获取PTE中的物理页帧号
(self.bits >> 10 & ((1usize << 44) - 1)).into()
}
/// Get the flags from the page table entry
pub fn flags(&self) -> PTEFlags {
pub fn flags(&self) -> PTEFlags { //获取PTE中的标记位
PTEFlags::from_bits(self.bits as u8).unwrap()
}
/// The page pointered by page table entry is valid?
pub fn is_valid(&self) -> bool {
pub fn is_valid(&self) -> bool { //判断PTE是否有效
(self.flags() & PTEFlags::V) != PTEFlags::empty()
}
/// The page pointered by page table entry is readable?
pub fn readable(&self) -> bool {
pub fn readable(&self) -> bool {
(self.flags() & PTEFlags::R) != PTEFlags::empty()
}
/// The page pointered by page table entry is writable?
Expand Down Expand Up @@ -88,6 +88,7 @@ impl PageTable {
}
}
/// Find PageTableEntry by VirtPageNum, create a frame for a 4KB page table if not exist
/// 返回vpn对应的pte
fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
let idxs = vpn.indexes();
let mut ppn = self.root_ppn;
Expand Down Expand Up @@ -132,13 +133,15 @@ impl PageTable {
result
}
/// set the map between virtual page number and physical page number
/// 为页表的虚拟页vpn增加一个对应的页表项,物理页号为ppn,标记为为flags
#[allow(unused)]
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
let pte = self.find_pte_create(vpn).unwrap();
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
}
/// remove the map between virtual page number and physical page number
/// 释放掉vpn对应的页表项
#[allow(unused)]
pub fn unmap(&mut self, vpn: VirtPageNum) {
let pte = self.find_pte(vpn).unwrap();
Expand All @@ -150,6 +153,7 @@ impl PageTable {
self.find_pte(vpn).map(|pte| *pte)
}
/// get the token from the page table
/// 获取页表的根页表地址
pub fn token(&self) -> usize {
8usize << 60 | self.root_ppn.0
}
Expand Down Expand Up @@ -179,18 +183,14 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
}

/// 虚拟地址到物理地址的转换方法
//
pub fn translated_physical_address<T>(token: usize, ptr: *const T) -> *mut T {

let page_table: PageTable = PageTable::from_token(token);
let mut_va: VirtAddr = VirtAddr::from(ptr as usize);
let ppn: PhysAddr = page_table.translate(mut_va.floor()).unwrap().ppn().into();

let start: usize = ptr as usize;
let mut_va: VirtAddr = VirtAddr::from(start);
let vpn: VirtPageNum = mut_va.floor();
let ppn: PhysAddr = page_table.translate(vpn).unwrap().ppn().into();

let offset: usize =mut_va.page_offset();
let phys_addr: usize = ppn.into();
( offset+ phys_addr) as *mut T

(super::PhysAddr::from(ppn).0 + mut_va.page_offset()) as * mut T

}

Loading

0 comments on commit e8f87cf

Please sign in to comment.