//! memory set, area //! and the inactive page table use alloc::vec::Vec; use core::fmt::{Debug, Error, Formatter}; use super::*; use crate::paging::*; /// an inactive page table /// Note: InactivePageTable is not a PageTable /// but it can be activated and "become" a PageTable /// Why this trait is in this file?(seems should in paging/mod.rs) pub trait InactivePageTable { /// the active version of page table type Active: PageTable; /* ** @brief create a inactive page table with kernel memory mapped ** @retval InactivePageTable the created inactive page table */ fn new() -> Self; /* ** @brief create an inactive page table without kernel memory mapped ** @retval InactivePageTable the created inactive page table */ fn new_bare() -> Self; /* ** @brief temporarily active the page table and edit it ** @retval impl FnOnce(&mut Self::Active) ** the function of the editing action, ** which takes a temporarily activated page table as param ** @retval none */ fn edit(&mut self, f: impl FnOnce(&mut Self::Active)); /* ** @brief activate the inactive page table ** @retval none */ unsafe fn activate(&self); /* ** @brief execute function with this inactive page table ** @param f: impl FnOnce() the function to be executed ** @retval none */ unsafe fn with(&self, f: impl FnOnce() -> T) -> T; /* ** @brief get the token of the inactive page table ** @retval usize the token of the inactive page table */ fn token(&self) -> usize; /// Why the methods below are in this trait? /* ** @brief allocate a frame for use ** @retval Option the physics address of the beginning of allocated frame, if present */ fn alloc_frame() -> Option; /* ** @brief deallocate a frame for use ** @param PhysAddr the physics address of the beginning of frame to be deallocated ** @retval none */ fn dealloc_frame(target: PhysAddr); } /// a continuous memory space when the same attribute /// like `vma_struct` in ucore #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub struct MemoryArea { start_addr: VirtAddr, end_addr: VirtAddr, phys_start_addr: Option, flags: MemoryAttr, name: &'static str, } impl MemoryArea { /* ** @brief create a memory area from virtual address ** @param start_addr: VirtAddr the virtual address of beginning of the area ** @param end_addr: VirtAddr the virtual address of end of the area ** @param flags: MemoryAttr the common memory attribute of the memory area ** @param name: &'static str the name of the memory area ** @retval MemoryArea the memory area created */ pub fn new(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self { assert!(start_addr <= end_addr, "invalid memory area"); MemoryArea { start_addr, end_addr, phys_start_addr: None, flags, name } } /* ** @brief create a memory area from virtual address which is identically mapped ** @param start_addr: VirtAddr the virtual address of beginning of the area ** @param end_addr: VirtAddr the virtual address of end of the area ** @param flags: MemoryAttr the common memory attribute of the memory area ** @param name: &'static str the name of the memory area ** @retval MemoryArea the memory area created */ pub fn new_identity(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self { assert!(start_addr <= end_addr, "invalid memory area"); MemoryArea { start_addr, end_addr, phys_start_addr: Some(start_addr), flags, name } } /* ** @brief create a memory area from physics address ** @param start_addr: PhysAddr the physics address of beginning of the area ** @param end_addr: PhysAddr the physics address of end of the area ** @param offset: usiz the offset between physics address and virtual address ** @param flags: MemoryAttr the common memory attribute of the memory area ** @param name: &'static str the name of the memory area ** @retval MemoryArea the memory area created */ pub fn new_physical(phys_start_addr: PhysAddr, phys_end_addr: PhysAddr, offset: usize, flags: MemoryAttr, name: &'static str) -> Self { let start_addr = phys_start_addr + offset; let end_addr = phys_end_addr + offset; assert!(start_addr <= end_addr, "invalid memory area"); let phys_start_addr = Some(phys_start_addr); MemoryArea { start_addr, end_addr, phys_start_addr, flags, name } } /* ** @brief get slice of the content in the memory area ** @retval &[u8] the slice of the content in the memory area */ pub unsafe fn as_slice(&self) -> &[u8] { use core::slice; slice::from_raw_parts(self.start_addr as *const u8, self.end_addr - self.start_addr) } /* ** @brief get mutable slice of the content in the memory area ** @retval &mut[u8] the mutable slice of the content in the memory area */ pub unsafe fn as_slice_mut(&self) -> &mut [u8] { use core::slice; slice::from_raw_parts_mut(self.start_addr as *mut u8, self.end_addr - self.start_addr) } /* ** @brief test whether a virtual address is in the memory area ** @param addr: VirtAddr the virtual address to test ** @retval bool whether the virtual address is in the memory area */ pub fn contains(&self, addr: VirtAddr) -> bool { addr >= self.start_addr && addr < self.end_addr } /* ** @brief test whether the memory area is overlap with another memory area ** @param other: &MemoryArea another memory area to test ** @retval bool whether the memory area is overlap with another memory area */ fn is_overlap_with(&self, other: &MemoryArea) -> bool { let p0 = Page::of_addr(self.start_addr); let p1 = Page::of_addr(self.end_addr - 1) + 1; let p2 = Page::of_addr(other.start_addr); let p3 = Page::of_addr(other.end_addr - 1) + 1; !(p1 <= p2 || p0 >= p3) } /* ** @brief map the memory area to the physice address in a page table ** @param pt: &mut T::Active the page table to use ** @retval none */ fn map(&self, pt: &mut T::Active) { match self.phys_start_addr { Some(phys_start) => { for page in Page::range_of(self.start_addr, self.end_addr) { let addr = page.start_address(); let target = page.start_address() - self.start_addr + phys_start; self.flags.apply(pt.map(addr, target)); } } None => { for page in Page::range_of(self.start_addr, self.end_addr) { let addr = page.start_address(); let target = T::alloc_frame().expect("failed to allocate frame"); self.flags.apply(pt.map(addr, target)); // for frame delayed allocation // let entry = pt.map(addr,0); // self.flags.apply(entry); // let entry = pt.get_entry(addr).expect("fail to get entry"); // entry.set_present(false); // entry.update(); } } }; } /* ** @brief unmap the memory area from the physice address in a page table ** @param pt: &mut T::Active the page table to use ** @retval none */ fn unmap(&self, pt: &mut T::Active) { for page in Page::range_of(self.start_addr, self.end_addr) { let addr = page.start_address(); if self.phys_start_addr.is_none() { if pt.get_entry(addr).expect("fail to get entry").present(){ let target = pt.get_entry(addr).expect("fail to get entry").target(); T::dealloc_frame(target); } else{ // set valid for pt.unmap function pt.get_entry(addr).expect("fail to get entry").set_present(true); } } pt.unmap(addr); } } pub fn get_start_addr(&self) -> VirtAddr { self.start_addr } pub fn get_end_addr(&self) -> VirtAddr{ self.end_addr } pub fn get_flags(&self) -> &MemoryAttr{ &self.flags } } /// The attributes of the memory #[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] pub struct MemoryAttr { user: bool, readonly: bool, execute: bool, hide: bool, mmio: usize, } impl MemoryAttr { /* ** @brief set the memory attribute's user bit ** @retval MemoryAttr the memory attribute itself */ pub fn user(mut self) -> Self { self.user = true; self } /* ** @brief set the memory attribute's readonly bit ** @retval MemoryAttr the memory attribute itself */ pub fn readonly(mut self) -> Self { self.readonly = true; self } /* ** @brief set the memory attribute's execute bit ** @retval MemoryAttr the memory attribute itself */ pub fn execute(mut self) -> Self { self.execute = true; self } /* ** @brief set the MMIO type ** @retval MemoryAttr the memory attribute itself */ pub fn mmio(mut self, value: usize) -> Self { self.mmio = value; self } /* ** @brief set the memory attribute's hide bit ** @retval MemoryAttr the memory attribute itself */ pub fn hide(mut self) -> Self { self.hide = true; self } /* ** @brief apply the memory attribute to a page table entry ** @param entry: &mut impl Entry ** the page table entry to apply the attribute ** @retval none */ fn apply(&self, entry: &mut impl Entry) { if self.user { entry.set_user(true); } if self.readonly { entry.set_writable(false); } if self.execute { entry.set_execute(true); } if self.mmio != 0 { entry.set_mmio(self.mmio); } if self.hide { entry.set_present(false); } if self.user || self.readonly || self.execute || self.mmio != 0 || self.hide { entry.update(); } } } /// set of memory space with multiple memory area with associated page table and stack space /// like `mm_struct` in ucore pub struct MemorySet { areas: Vec, page_table: T, } impl MemorySet { /* ** @brief create a memory set ** @retval MemorySet the memory set created */ pub fn new() -> Self { MemorySet { areas: Vec::::new(), page_table: T::new(), } } pub fn new_bare() -> Self { MemorySet { areas: Vec::::new(), page_table: T::new_bare(), } } /* ** @brief find the memory area from virtual address ** @param addr: VirtAddr the virtual address to find ** @retval Option<&MemoryArea> the memory area with the virtual address, if presented */ pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { self.areas.iter().find(|area| area.contains(addr)) } /* ** @brief add the memory area to the memory set ** @param area: MemoryArea the memory area to add ** @retval none */ pub fn push(&mut self, area: MemoryArea) { assert!(self.areas.iter() .find(|other| area.is_overlap_with(other)) .is_none(), "memory area overlap"); self.page_table.edit(|pt| area.map::(pt)); self.areas.push(area); } /* ** @brief get iterator of the memory area ** @retval impl Iterator ** the memory area iterator */ pub fn iter(&self) -> impl Iterator { self.areas.iter() } pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) { self.page_table.edit(f); } /* ** @brief execute function with the associated page table ** @param f: impl FnOnce() the function to be executed ** @retval none */ pub unsafe fn with(&self, f: impl FnOnce()) { self.page_table.with(f); } /* ** @brief activate the associated page table ** @retval none */ pub unsafe fn activate(&self) { self.page_table.activate(); } /* ** @brief get the token of the associated page table ** @retval usize the token of the inactive page table */ pub fn token(&self) -> usize { self.page_table.token() } /* ** @brief clear the memory set ** @retval none */ pub fn clear(&mut self) { let Self { ref mut page_table, ref mut areas, .. } = self; page_table.edit(|pt| { for area in areas.iter() { area.unmap::(pt); } }); areas.clear(); } /* ** @brief get the mutable reference for the inactive page table ** @retval: &mut T the mutable reference of the inactive page table */ pub fn get_page_table_mut(&mut self) -> &mut T{ &mut self.page_table } } impl Clone for MemorySet { fn clone(&self) -> Self { let mut page_table = T::new(); page_table.edit(|pt| { for area in self.areas.iter() { area.map::(pt); } }); info!("finish map in clone!"); MemorySet { areas: self.areas.clone(), page_table, } } } impl Drop for MemorySet { fn drop(&mut self) { info!("come into drop func for memoryset"); self.clear(); } } impl Debug for MemorySet { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { f.debug_list() .entries(self.areas.iter()) .finish() } }