commit
aa5bd3041b
@ -1,416 +0,0 @@
|
||||
//! 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<T>(&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<PhysAddr> the physics address of the beginning of allocated frame, if present
|
||||
*/
|
||||
fn alloc_frame() -> Option<PhysAddr>;
|
||||
/*
|
||||
** @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<PhysAddr>,
|
||||
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<T: InactivePageTable>(&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<T: InactivePageTable>(&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: u8,
|
||||
}
|
||||
|
||||
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: u8) -> 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<T: InactivePageTable> {
|
||||
areas: Vec<MemoryArea>,
|
||||
page_table: T,
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> MemorySet<T> {
|
||||
/*
|
||||
** @brief create a memory set
|
||||
** @retval MemorySet<T> the memory set created
|
||||
*/
|
||||
pub fn new() -> Self {
|
||||
MemorySet {
|
||||
areas: Vec::<MemoryArea>::new(),
|
||||
page_table: T::new(),
|
||||
}
|
||||
}
|
||||
pub fn new_bare() -> Self {
|
||||
MemorySet {
|
||||
areas: Vec::<MemoryArea>::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::<T>(pt));
|
||||
self.areas.push(area);
|
||||
}
|
||||
/*
|
||||
** @brief get iterator of the memory area
|
||||
** @retval impl Iterator<Item=&MemoryArea>
|
||||
** the memory area iterator
|
||||
*/
|
||||
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
|
||||
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::<T>(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<T: InactivePageTable> Clone for MemorySet<T> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut page_table = T::new();
|
||||
page_table.edit(|pt| {
|
||||
for area in self.areas.iter() {
|
||||
area.map::<T>(pt);
|
||||
}
|
||||
});
|
||||
info!("finish map in clone!");
|
||||
MemorySet {
|
||||
areas: self.areas.clone(),
|
||||
page_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> Drop for MemorySet<T> {
|
||||
fn drop(&mut self) {
|
||||
info!("come into drop func for memoryset");
|
||||
self.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> Debug for MemorySet<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
f.debug_list()
|
||||
.entries(self.areas.iter())
|
||||
.finish()
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ByFrame<T: FrameAllocator> {
|
||||
flags: MemoryAttr,
|
||||
allocator: T,
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> MemoryHandler for ByFrame<T> {
|
||||
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let target = self.allocator.alloc().expect("failed to allocate frame");
|
||||
self.flags.apply(pt.map(addr, target));
|
||||
}
|
||||
|
||||
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let target = pt.get_entry(addr).expect("fail to get entry").target();
|
||||
self.allocator.dealloc(target);
|
||||
pt.unmap(addr);
|
||||
}
|
||||
|
||||
fn page_fault_handler(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> ByFrame<T> {
|
||||
pub fn new(flags: MemoryAttr, allocator: T) -> Self {
|
||||
ByFrame { flags, allocator }
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Delay<T: FrameAllocator> {
|
||||
flags: MemoryAttr,
|
||||
allocator: T,
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> MemoryHandler for Delay<T> {
|
||||
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let entry = pt.map(addr, 0);
|
||||
entry.set_present(false);
|
||||
entry.update();
|
||||
}
|
||||
|
||||
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
if entry.present() {
|
||||
self.allocator.dealloc(entry.target());
|
||||
pt.unmap(addr);
|
||||
}
|
||||
}
|
||||
|
||||
fn page_fault_handler(&self, pt: &mut PageTable, addr: VirtAddr) -> bool {
|
||||
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||
if entry.present() {
|
||||
// not a delay case
|
||||
return false;
|
||||
}
|
||||
let frame = self.allocator.alloc().expect("failed to alloc frame");
|
||||
entry.set_target(frame);
|
||||
self.flags.apply(entry);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> Delay<T> {
|
||||
pub fn new(flags: MemoryAttr, allocator: T) -> Self {
|
||||
Delay { flags, allocator }
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub struct Linear {
|
||||
offset: isize,
|
||||
flags: MemoryAttr,
|
||||
}
|
||||
|
||||
impl MemoryHandler for Linear {
|
||||
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn map(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
let target = (addr as isize + self.offset) as PhysAddr;
|
||||
self.flags.apply(pt.map(addr, target));
|
||||
}
|
||||
|
||||
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||
pt.unmap(addr);
|
||||
}
|
||||
|
||||
fn page_fault_handler(&self, _pt: &mut PageTable, _addr: VirtAddr) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Linear {
|
||||
pub fn new(offset: isize, flags: MemoryAttr) -> Self {
|
||||
Linear { offset, flags }
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
use super::*;
|
||||
|
||||
// here may be a interesting part for lab
|
||||
pub trait MemoryHandler: Debug + 'static {
|
||||
fn box_clone(&self) -> Box<MemoryHandler>;
|
||||
fn map(&self, pt: &mut PageTable, addr: VirtAddr);
|
||||
fn unmap(&self, pt: &mut PageTable, addr: VirtAddr);
|
||||
fn page_fault_handler(&self, pt: &mut PageTable, addr: VirtAddr) -> bool;
|
||||
}
|
||||
|
||||
impl Clone for Box<MemoryHandler> {
|
||||
fn clone(&self) -> Box<MemoryHandler> {
|
||||
self.box_clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FrameAllocator: Debug + Clone + 'static {
|
||||
fn alloc(&self) -> Option<PhysAddr>;
|
||||
fn dealloc(&self, target: PhysAddr);
|
||||
}
|
||||
|
||||
mod linear;
|
||||
mod byframe;
|
||||
mod delay;
|
||||
//mod swap;
|
||||
|
||||
pub use self::linear::Linear;
|
||||
pub use self::byframe::ByFrame;
|
||||
pub use self::delay::Delay;
|
@ -0,0 +1,274 @@
|
||||
//! memory set, area
|
||||
//! and the inactive page table
|
||||
|
||||
use alloc::{vec::Vec, boxed::Box};
|
||||
use core::fmt::{Debug, Error, Formatter};
|
||||
use super::*;
|
||||
use crate::paging::*;
|
||||
use self::handler::MemoryHandler;
|
||||
|
||||
pub mod handler;
|
||||
|
||||
/// a continuous memory space when the same attribute
|
||||
/// like `vma_struct` in ucore
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryArea {
|
||||
start_addr: VirtAddr,
|
||||
end_addr: VirtAddr,
|
||||
handler: Box<MemoryHandler>,
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
impl MemoryArea {
|
||||
/*
|
||||
** @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] {
|
||||
::core::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] {
|
||||
::core::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 PageTable) {
|
||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||
self.handler.map(pt, page.start_address());
|
||||
}
|
||||
}
|
||||
/*
|
||||
** @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 PageTable) {
|
||||
for page in Page::range_of(self.start_addr, self.end_addr) {
|
||||
self.handler.unmap(pt, page.start_address());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The attributes of the memory
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct MemoryAttr {
|
||||
user: bool,
|
||||
readonly: bool,
|
||||
execute: bool,
|
||||
mmio: u8,
|
||||
}
|
||||
|
||||
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: u8) -> Self {
|
||||
self.mmio = value;
|
||||
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
|
||||
*/
|
||||
pub fn apply(&self, entry: &mut Entry) {
|
||||
entry.set_present(true);
|
||||
entry.set_user(self.user);
|
||||
entry.set_writable(!self.readonly);
|
||||
entry.set_execute(self.execute);
|
||||
entry.set_mmio(self.mmio);
|
||||
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<T: InactivePageTable> {
|
||||
areas: Vec<MemoryArea>,
|
||||
page_table: T,
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> MemorySet<T> {
|
||||
/*
|
||||
** @brief create a memory set
|
||||
** @retval MemorySet<T> 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, start_addr: VirtAddr, end_addr: VirtAddr, handler: impl MemoryHandler, name: &'static str) {
|
||||
assert!(start_addr <= end_addr, "invalid memory area");
|
||||
let area = MemoryArea { start_addr, end_addr, handler: Box::new(handler), name };
|
||||
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<Item=&MemoryArea>
|
||||
** the memory area iterator
|
||||
*/
|
||||
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
|
||||
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
|
||||
}
|
||||
|
||||
pub fn page_fault_handler(&mut self, addr: VirtAddr) -> bool {
|
||||
let area = self.areas.iter().find(|area| area.contains(addr));
|
||||
match area {
|
||||
Some(area) => self.page_table.edit(|pt| area.handler.page_fault_handler(pt, addr)),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> Clone for MemorySet<T> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut page_table = T::new();
|
||||
page_table.edit(|pt| {
|
||||
for area in self.areas.iter() {
|
||||
area.map(pt);
|
||||
}
|
||||
});
|
||||
MemorySet {
|
||||
areas: self.areas.clone(),
|
||||
page_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> Drop for MemorySet<T> {
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: InactivePageTable> Debug for MemorySet<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
f.debug_list()
|
||||
.entries(self.areas.iter())
|
||||
.finish()
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
//! Helper functions
|
||||
|
||||
use super::*;
|
||||
|
||||
pub trait PageTableExt: PageTable {
|
||||
const TEMP_PAGE_ADDR: VirtAddr = 0xcafeb000;
|
||||
|
||||
fn with_temporary_map<T, D>(&mut self, target: PhysAddr, f: impl FnOnce(&mut Self, &mut D) -> T) -> T {
|
||||
self.map(Self::TEMP_PAGE_ADDR, target);
|
||||
let data = unsafe { &mut *(self.get_page_slice_mut(Self::TEMP_PAGE_ADDR).as_ptr() as *mut D) };
|
||||
let ret = f(self, data);
|
||||
self.unmap(Self::TEMP_PAGE_ADDR);
|
||||
ret
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 316 KiB |
Binary file not shown.
Loading…
Reference in new issue