From aecb85d5e777b41471928feac12f89ade31b04a8 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Tue, 10 Jul 2018 21:54:16 +0800 Subject: [PATCH] Move MemorySet out to memory crate --- crate/memory/src/addr.rs | 60 +++++++ crate/memory/src/lib.rs | 6 +- .../memory => crate/memory/src}/memory_set.rs | 150 ++++++------------ 3 files changed, 114 insertions(+), 102 deletions(-) create mode 100644 crate/memory/src/addr.rs rename {src/memory => crate/memory/src}/memory_set.rs (55%) diff --git a/crate/memory/src/addr.rs b/crate/memory/src/addr.rs new file mode 100644 index 0000000..aaaae3b --- /dev/null +++ b/crate/memory/src/addr.rs @@ -0,0 +1,60 @@ +use core::ops::{Add, AddAssign}; + +pub type VirtAddr = usize; +pub type PhysAddr = usize; +pub const PAGE_SIZE: usize = 1 << 12; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Page { + number: usize, +} + +impl Page { + pub fn start_address(&self) -> VirtAddr { + self.number * PAGE_SIZE + } + pub fn of_addr(addr: VirtAddr) -> Self { + Page { number: addr / PAGE_SIZE } + } + pub fn range_of(begin: VirtAddr, end: VirtAddr) -> PageRange { + PageRange { + start: Page::of_addr(begin), + end: Page::of_addr(end - 1) + 1, + } + } +} + +impl Add for Page { + type Output = Self; + fn add(self, rhs: usize) -> Self::Output { + Page { number: self.number + rhs } + } +} + +impl AddAssign for Page { + fn add_assign(&mut self, rhs: usize) { + *self = self.clone() + rhs; + } +} + +/// A range of pages with exclusive upper bound. +#[derive(Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub struct PageRange { + start: Page, + end: Page, +} + +impl Iterator for PageRange { + type Item = Page; + + fn next(&mut self) -> Option { + if self.start < self.end { + let page = self.start.clone(); + self.start += 1; + Some(page) + } else { + None + } + } +} \ No newline at end of file diff --git a/crate/memory/src/lib.rs b/crate/memory/src/lib.rs index e48802d..cd647ad 100644 --- a/crate/memory/src/lib.rs +++ b/crate/memory/src/lib.rs @@ -15,7 +15,7 @@ pub mod paging; #[cfg(target_arch = "x86_64")] pub mod cow; pub mod swap; +pub mod memory_set; +mod addr; -type VirtAddr = usize; -type PhysAddr = usize; -const PAGE_SIZE: usize = 4096; \ No newline at end of file +pub use addr::*; \ No newline at end of file diff --git a/src/memory/memory_set.rs b/crate/memory/src/memory_set.rs similarity index 55% rename from src/memory/memory_set.rs rename to crate/memory/src/memory_set.rs index 7cba816..3deba1f 100644 --- a/src/memory/memory_set.rs +++ b/crate/memory/src/memory_set.rs @@ -1,6 +1,19 @@ use alloc::vec::Vec; use core::fmt::{Debug, Error, Formatter}; +use core::marker::PhantomData; use super::*; +use paging::*; + +pub trait InactivePageTable { + type Active: PageTable; + + fn new() -> Self; + fn edit(&mut self, f: impl FnOnce(&mut Self::Active)); + unsafe fn activate(&self) -> Self; + + fn alloc_frame() -> Option; + fn dealloc_frame(target: PhysAddr); +} /// 一片连续内存空间,有相同的访问权限 /// 对应ucore中 `vma_struct` @@ -16,33 +29,16 @@ pub struct MemoryArea { impl MemoryArea { 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, - } + MemoryArea { start_addr, end_addr, phys_start_addr: None, flags, name } } 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(PhysAddr::new(start_addr as u64)), - flags, - name, - } + MemoryArea { start_addr, end_addr, phys_start_addr: Some(start_addr), flags, name } } - pub fn new_kernel(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self { + pub fn new_offset(start_addr: VirtAddr, end_addr: VirtAddr, offset: isize, flags: MemoryAttr, name: &'static str) -> Self { assert!(start_addr <= end_addr, "invalid memory area"); - MemoryArea { - start_addr, - end_addr, - phys_start_addr: Some(PhysAddr::from_kernel_virtual(start_addr)), - flags, - name, - } + let phys_start_addr = Some((start_addr as isize + offset) as usize); + MemoryArea { start_addr, end_addr, phys_start_addr, flags, name } } pub unsafe fn as_slice(&self) -> &[u8] { use core::slice; @@ -62,28 +58,30 @@ impl MemoryArea { let p3 = Page::of_addr(other.end_addr - 1) + 1; !(p1 <= p2 || p0 >= p3) } - fn map(&self, pt: &mut ActivePageTable) { + 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 frame = Frame::of_addr(phys_start.get() + page.start_address().as_u64() as usize - self.start_addr); - self.flags.apply(pt.map_to(page, frame)); + let addr = page.start_address(); + let target = phys_start + page.start_address() - self.start_addr; + self.flags.apply(pt.map(addr, target)); } } None => { for page in Page::range_of(self.start_addr, self.end_addr) { - let frame = alloc_frame(); - self.flags.apply(pt.map_to(page, frame)); + let addr = page.start_address(); + let target = T::alloc_frame().expect("failed to allocate frame"); + self.flags.apply(pt.map(addr, target)); } } } } - fn unmap(&self, pt: &mut ActivePageTable) { + fn unmap(&self, pt: &mut T::Active) { for page in Page::range_of(self.start_addr, self.end_addr) { - let addr = page.start_address().as_u64() as usize; + let addr = page.start_address(); if self.phys_start_addr.is_none() { - let frame = Frame::of_addr(pt.get_entry(addr).target()); - dealloc_frame(frame); + let target = pt.get_entry(addr).target(); + T::dealloc_frame(target); } pt.unmap(addr); } @@ -126,18 +124,16 @@ impl MemoryAttr { /// 内存空间集合,包含若干段连续空间 /// 对应ucore中 `mm_struct` -pub struct MemorySet { +pub struct MemorySet { areas: Vec, - page_table: InactivePageTable, - kstack: Option, + page_table: T, } -impl MemorySet { - pub fn new(stack_size_in_pages: usize) -> Self { +impl MemorySet { + pub fn new() -> Self { MemorySet { areas: Vec::::new(), - page_table: new_page_table_with_kernel(), - kstack: Some(alloc_stack(stack_size_in_pages)), + page_table: T::new(), } } /// Used for remap_kernel() where heap alloc is unavailable @@ -146,8 +142,7 @@ impl MemorySet { let cap = slice.len() / size_of::(); MemorySet { areas: Vec::::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), - page_table: new_page_table(), - kstack: None, + page_table: T::new(), } } pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { @@ -157,82 +152,39 @@ impl MemorySet { assert!(self.areas.iter() .find(|other| area.is_overlap_with(other)) .is_none(), "memory area overlap"); - - active_table().with(&mut self.page_table, |mapper| area.map(mapper)); - + self.page_table.edit(|pt| area.map::(pt)); self.areas.push(area); } pub fn iter(&self) -> impl Iterator { self.areas.iter() } - pub fn with(&self, f: impl FnOnce()) { - let current = unsafe { InactivePageTable::from_cr3() }; - self.page_table.switch(); + pub unsafe fn with(&self, f: impl FnOnce()) { + let old = self.page_table.activate(); f(); - current.switch(); - use core::mem; - mem::forget(current); - } - pub fn switch(&self) { - self.page_table.switch(); - } - pub fn set_kstack(&mut self, stack: Stack) { - assert!(self.kstack.is_none()); - self.kstack = Some(stack); + old.activate(); } - pub fn kstack_top(&self) -> usize { - self.kstack.as_ref().unwrap().top() + pub unsafe fn activate(&self) { + self.page_table.activate(); } - pub fn clone(&self, stack_size_in_pages: usize) -> Self { - let mut page_table = new_page_table_with_kernel(); - active_table().with(&mut page_table, |mapper| { + pub fn clone(&self) -> Self { + let mut page_table = T::new(); + page_table.edit(|pt| { for area in self.areas.iter() { - area.map(mapper); + area.map::(pt); } }); MemorySet { areas: self.areas.clone(), page_table, - kstack: Some(alloc_stack(stack_size_in_pages)), } } - /// Only for SMP - pub fn _page_table_addr(&self) -> PhysAddr { - use core::mem; - unsafe { mem::transmute_copy::<_, Frame>(&self.page_table) }.start_address() - } -} - -impl Drop for MemorySet { - fn drop(&mut self) { - debug!("MemorySet dropping"); - let Self { ref mut page_table, ref areas, .. } = self; - active_table().with(page_table, |mapper| { + 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(mapper); + area.unmap::(pt); } - }) - } -} - -impl Debug for MemorySet { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - f.debug_list() - .entries(self.areas.iter()) - .finish() + }); + areas.clear(); } } - -fn new_page_table() -> InactivePageTable { - let frame = alloc_frame(); - let mut active_table = active_table(); - InactivePageTable::new(frame, &mut active_table) -} - -fn new_page_table_with_kernel() -> InactivePageTable { - let frame = alloc_frame(); - let mut active_table = active_table(); - let mut page_table = InactivePageTable::new(frame, &mut active_table); - page_table.map_kernel(&mut active_table); - page_table -}