diff --git a/crate/memory/Cargo.toml b/crate/memory/Cargo.toml index dcc9ec1..fb4fe38 100644 --- a/crate/memory/Cargo.toml +++ b/crate/memory/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["WangRunji "] [dependencies] +log = "0.4" \ No newline at end of file diff --git a/crate/memory/src/addr.rs b/crate/memory/src/addr.rs index 4b9173f..f38ec26 100644 --- a/crate/memory/src/addr.rs +++ b/crate/memory/src/addr.rs @@ -1,4 +1,6 @@ use core::ops::{Add, AddAssign}; +use super::paging::*; +use super::memory_set::*; pub type VirtAddr = usize; pub type PhysAddr = usize; @@ -73,4 +75,45 @@ impl Iterator for PageRange { None } } +} + +/// frame for the swapmanager +#[derive(Debug, Copy, Clone, PartialOrd, Ord)] +#[repr(C)] +pub struct Frame { + page_table: usize, // the raw pointer for the frame's memory set's inactive page table + virtaddr: VirtAddr, // the virtual addr for the frame + token: usize, // the token for frame +} + +impl Frame{ + pub fn get_page_table(&self) -> usize { + self.page_table + } + + pub fn get_virtaddr(&self) -> VirtAddr { + self.virtaddr + } + + pub fn get_token(&self) -> usize{ + self.token + } + + pub fn new(pt: usize, addr: VirtAddr, pttoken: usize) -> Self{ + Frame { + page_table: pt, + virtaddr: addr, + token: pttoken, + } + } +} + +impl PartialEq for Frame{ + fn eq(&self, other: &Frame) -> bool { + self.token == other.token && self.virtaddr == other.virtaddr + } +} + +impl Eq for Frame{ + } \ No newline at end of file diff --git a/crate/memory/src/lib.rs b/crate/memory/src/lib.rs index 808d983..248feb6 100644 --- a/crate/memory/src/lib.rs +++ b/crate/memory/src/lib.rs @@ -2,6 +2,8 @@ #![feature(alloc)] extern crate alloc; +#[macro_use] +extern crate log; // To use `println!` in test #[cfg(test)] diff --git a/crate/memory/src/memory_set.rs b/crate/memory/src/memory_set.rs index d2c4d3c..d51a669 100644 --- a/crate/memory/src/memory_set.rs +++ b/crate/memory/src/memory_set.rs @@ -66,6 +66,8 @@ pub trait InactivePageTable { ** @retval Stack the stack allocated */ fn alloc_stack() -> Stack; + + unsafe fn with_retval(&self, f: impl FnOnce() -> T) -> T; } /// a continuous memory space when the same attribute @@ -367,6 +369,14 @@ impl MemorySet { }); 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 { @@ -387,6 +397,7 @@ impl Clone for MemorySet { impl Drop for MemorySet { fn drop(&mut self) { + info!("come into drop func for memoryset"); self.clear(); } } diff --git a/crate/memory/src/paging/mod.rs b/crate/memory/src/paging/mod.rs index 32c7d92..8733dca 100644 --- a/crate/memory/src/paging/mod.rs +++ b/crate/memory/src/paging/mod.rs @@ -3,6 +3,7 @@ //! Implemented for every architecture, used by OS. use super::*; +use super::memory_set::InactivePageTable; #[cfg(test)] pub use self::mock_page_table::MockPageTable; diff --git a/crate/memory/src/swap/fifo.rs b/crate/memory/src/swap/fifo.rs index e30ddd3..03ab226 100644 --- a/crate/memory/src/swap/fifo.rs +++ b/crate/memory/src/swap/fifo.rs @@ -3,32 +3,36 @@ use alloc::collections::VecDeque; use super::*; + #[derive(Default)] -pub struct FifoSwapManager { - deque: VecDeque, +pub struct FifoSwapManager { + deque: VecDeque, } impl SwapManager for FifoSwapManager { fn tick(&mut self) {} - fn push(&mut self, addr: usize) { - self.deque.push_back(addr); + fn push(&mut self, frame: Frame) { + debug!("SwapManager push token: {:x?} vaddr: {:x?}", frame.get_token(), frame.get_virtaddr()); + self.deque.push_back(frame); } - fn remove(&mut self, addr: usize) { + fn remove(&mut self, token: usize, addr: VirtAddr) { + debug!("SwapManager remove token: {:x?} vaddr: {:x?}", token, addr); let id = self.deque.iter() - .position(|&x| x == addr) + .position(|ref x| x.get_virtaddr() == addr && x.get_token() == token) .expect("address not found"); self.deque.remove(id); } - fn pop(&mut self, _: &mut T, _: &mut S) -> Option + fn pop(&mut self, _: &mut T, _: &mut S) -> Option where T: PageTable, S: Swapper { self.deque.pop_front() } } +/* #[cfg(test)] mod test { use super::*; @@ -49,4 +53,5 @@ mod test { 10, 11, 11]; test_manager(FifoSwapManager::default(), &ops, &pgfault_count); } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/crate/memory/src/swap/mock_swapper.rs b/crate/memory/src/swap/mock_swapper.rs index ef6a57c..36effe7 100644 --- a/crate/memory/src/swap/mock_swapper.rs +++ b/crate/memory/src/swap/mock_swapper.rs @@ -4,7 +4,6 @@ //! Used to test page table operation use super::Swapper; -//use alloc::btree_map::BTreeMap; use alloc::collections::BTreeMap; use core::mem::uninitialized; diff --git a/crate/memory/src/swap/mod.rs b/crate/memory/src/swap/mod.rs index d3b894b..d568f91 100644 --- a/crate/memory/src/swap/mod.rs +++ b/crate/memory/src/swap/mod.rs @@ -8,19 +8,23 @@ use super::*; use super::paging::*; +use super::memory_set::InactivePageTable; +use super::addr::Frame; +use alloc::rc::Rc; use core::ops::{Deref, DerefMut}; //pub use self::fifo::FifoSwapManager; -pub use self::enhanced_clock::EnhancedClockSwapManager; +//pub use self::enhanced_clock::EnhancedClockSwapManager; pub mod fifo; -mod enhanced_clock; +//mod enhanced_clock; pub mod mock_swapper; //#[cfg(test)] //mod mock_swapper; /// Manage all swappable pages, decide which to swap out pub trait SwapManager { + //type Inactive: InactivePageTable; /* ** @brief update intarnal state pre tick ** Called when tick interrupt occured @@ -30,25 +34,26 @@ pub trait SwapManager { /* ** @brief update intarnal state when page is pushed into memory ** Called when map a swappable page into the memory - ** @param addr: VirtAddr the virual address of the page pushed into memory + ** @param frame: Frame the Frame recording the swappable frame info ** @retval none */ - fn push(&mut self, addr: VirtAddr); + fn push(&mut self, frame: Frame); /* ** @brief update intarnal state when page is removed from memory ** Called to delete the addr entry from the swap manager + ** @param token: usize the inactive page table token for the virtual address ** @param addr: VirtAddr the virual address of the page removed from memory ** @retval none */ - fn remove(&mut self, addr: VirtAddr); + fn remove(&mut self, token: usize, addr: VirtAddr); /* ** @brief select swap out victim when there is need to swap out a page ** (The params is only used by `EnhancedClockSwapManager` currently) ** @param page_table: &mut T the current page table ** @param swapper: &mut S the swapper used - ** @retval Option the virual address of the victim page, if present + ** @retval Option the Frame of the victim page, if present */ - fn pop(&mut self, page_table: &mut T, swapper: &mut S) -> Option + fn pop(&mut self, page_table: &mut T, swapper: &mut S) -> Option where T: PageTable, S: Swapper; } @@ -100,11 +105,52 @@ impl SwapExt { } /* - ** @brief set a virtual address (a page) swappable + ** @brief set a page swappable + ** @param pt: *mut T2 the raw pointer for the target page's inactive page table ** @param addr: VirtAddr the target page's virtual address */ - pub fn set_swappable(&mut self, addr: VirtAddr){ - self.swap_manager.push(addr); + pub fn set_swappable(&mut self, pt: *mut T2, addr: VirtAddr){ + let token = unsafe{ + (*pt).token() + }; + let frame = Frame::new(pt as usize, addr, token); + self.swap_manager.push(frame); + } + + /* + ** @brief remove a page (given virtual address) from swappable pages, if the page is swapped, swap in at first + ** @param pt: *mut T2 the raw pointer for the target page's inactive page table + ** @param addr: VirtAddr the target page's virtual address + ** @param alloc_frame: the function to alloc a free physical frame for once + */ + pub unsafe fn remove_from_swappable(&mut self, pt: *mut T2, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr){ + trace!("come into remove_from swappable"); + let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self; + let targetpt = &mut *(pt); + let pttoken = { + debug!("the target page table token is {:x?}", targetpt.token()); + targetpt.token() + }; + debug!("try to change pagetable"); + let targetaddr = targetpt.with(||{ + let token = { + let entry = page_table.get_entry(addr); + if !entry.swapped() { + swap_manager.remove(pttoken, addr); + return; + } + let token = entry.target() / PAGE_SIZE; + let frame = alloc_frame(); + entry.set_target(frame); + entry.set_swapped(false); + entry.set_present(true); + entry.update(); + token + }; + let data = page_table.get_page_slice_mut(addr); + swapper.swap_in(token, data).unwrap(); + }); + trace!("come outof femove_from swappable"); } /* @@ -113,55 +159,72 @@ impl SwapExt { ** @param target: VirtAddr the target physics address ** @retval none */ + /* pub fn map_to_swappable(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut T::Entry { self.swap_manager.push(addr); self.map(addr, target) - } + }*/ + /* ** @brief Swap out any one of the swapped pages ** @retval Result ** the physics address of released frame if success, ** the error if failed */ - pub fn swap_out_any(&mut self) -> Result { - let victim = { + pub fn swap_out_any(&mut self) -> Result { + let victim: Option = { let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self; swap_manager.pop(page_table, swapper) }; + info!("swap out page {}", victim.unwrap().get_virtaddr()); match victim { None => Err(SwapError::NoSwapped), - Some(addr) => self.swap_out(addr), + Some(frame) => self.swap_out::(&frame), } } + /* ** @brief Swap out page - ** @param addr: VirtAddr the virual address of beginning of page + ** @param frame: Frame the Frame of page recording the page info ** @retval Result ** the physics address of the original map target frame if success, ** the error if failed */ - fn swap_out(&mut self, addr: VirtAddr) -> Result { - let data = self.page_table.get_page_slice_mut(addr); - let entry = self.page_table.get_entry(addr); - if entry.swapped() { - return Err(SwapError::AlreadySwapped); - } - let token = self.swapper.swap_out(data).map_err(|_| SwapError::IOError)?; - let target = entry.target(); - entry.set_target(token * PAGE_SIZE); - entry.set_swapped(true); - entry.set_present(false); - entry.update(); - Ok(target) + fn swap_out(&mut self, frame: &Frame) -> Result { + let Self {ref mut page_table, ref mut swap_manager, ref mut swapper} = self; + let ret = unsafe{ + let pt = &mut *(frame.get_page_table() as *mut T2); + pt.with_retval(||{ + //use core::slice; + //let data = unsafe { slice::from_raw_parts_mut((frame.virtaddr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) }; + let data = page_table.get_page_slice_mut(frame.get_virtaddr()); + let entry = page_table.get_entry(frame.get_virtaddr()); + if entry.swapped() { + return Err(SwapError::AlreadySwapped); + } + //assert!(!entry.swapped(), "Page already swapped!"); + let token = swapper.swap_out(data).map_err(|_| SwapError::IOError)?; + //let token = swapper.swap_out(data).unwrap(); + let target = entry.target(); + entry.set_target(token * PAGE_SIZE); + entry.set_swapped(true); + entry.set_present(false); + entry.update(); + Ok(target) + }) + }; + ret } /* - ** @brief map the virtual address to a target physics address and then swap in page data + ** @brief map the virtual address to a target physics address and then swap in page data, noted that the page should be in the current page table + ** @param pt: *mut T2 the raw pointer for the swapping page's inactive page table ** @param addr: VirtAddr the virual address of beginning of page - ** @param addr: PhysAddr the target physics address + ** @param target: PhysAddr the target physics address ** @retval Result<()), SwapError> ** the execute result, and the error if failed */ - fn swap_in(&mut self, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> { + fn swap_in(&mut self, pt: *mut T2, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> { + info!("come in to swap in"); let token = { let entry = self.page_table.get_entry(addr); if !entry.swapped() { @@ -176,12 +239,18 @@ impl SwapExt { }; let data = self.page_table.get_page_slice_mut(addr); self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?; - self.swap_manager.push(addr); + let pttoken = unsafe{ + (*pt).token() + }; + let frame = Frame::new(pt as usize, addr, pttoken); +; + self.swap_manager.push(frame); Ok(()) } /* ** @brief execute the swap process for page fault ** This function must be called whenever PageFault happens. + ** @param pt: *mut T2 the raw pointer for the target page's inactive page table (exactly the current page table) ** @param addr: VirtAddr the virual address of the page fault ** @param alloc_frame: impl FnOnce() -> PhysAddr ** the page allocation function @@ -189,14 +258,13 @@ impl SwapExt { ** of beginning of the page ** @retval bool whether swap in happens. */ - pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool { + pub fn page_fault_handler(&mut self, pt: *mut T2, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool { if !self.page_table.get_entry(addr).swapped() { return false; } // Allocate a frame, if failed, swap out a page - //let frame = alloc_frame().unwrap_or_else(|| self.swap_out_any().ok().unwrap()); let frame = alloc_frame(); - self.swap_in(addr, frame).ok().unwrap(); + self.swap_in(pt, addr, frame).ok().unwrap(); true } } @@ -226,6 +294,7 @@ impl DerefMut for SwapExt { } } +/* #[cfg(test)] mod test { use super::*; @@ -288,4 +357,5 @@ mod test { assert_eq!(*(*page_fault_count).borrow(), count); } } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/crate/process/src/processor.rs b/crate/process/src/processor.rs index f414dd0..a2358b7 100644 --- a/crate/process/src/processor.rs +++ b/crate/process/src/processor.rs @@ -257,6 +257,11 @@ impl Processor_ { &self.get(self.current_pid).context } + pub fn current_context_mut(&mut self) -> &mut T { + let id = self.current_pid; + &mut self.get_mut(id).context + } + /* ** @brief get pid of current process ** @param none diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index d8de26e..6c43a1a 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -235,6 +235,9 @@ dependencies = [ [[package]] name = "ucore-memory" version = "0.1.0" +dependencies = [ + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "ucore-process" diff --git a/kernel/src/arch/riscv32/paging.rs b/kernel/src/arch/riscv32/paging.rs index 9b36fe6..d9d525c 100644 --- a/kernel/src/arch/riscv32/paging.rs +++ b/kernel/src/arch/riscv32/paging.rs @@ -238,9 +238,9 @@ impl InactivePageTable for InactivePageTable0 { /* * @param: - * f: a function to do something for a muatable activepagetable + * f: a function to do something with the temporary modified activate page table * @brief: - * temporarily map the pagetable as an active page and apply f on the it + * temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table */ fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| { @@ -259,6 +259,10 @@ impl InactivePageTable for InactivePageTable0 { }); } + /* + * @brief: + * active self as the current active page table + */ unsafe fn activate(&self) { let old_frame = satp::read().frame(); let new_frame = self.p2_frame.clone(); @@ -269,6 +273,12 @@ impl InactivePageTable for InactivePageTable0 { } } + /* + * @param: + * f: the function to run when temporarily activate self as current page table + * @brief: + * Temporarily activate self and run the process + */ unsafe fn with(&self, f: impl FnOnce()) { let old_frame = satp::read().frame(); let new_frame = self.p2_frame.clone(); @@ -285,6 +295,37 @@ impl InactivePageTable for InactivePageTable0 { } } + /* + * @param: + * f: the function to run when temporarily activate self as current page table + * @brief: + * Temporarily activate self and run the process, and return the return value of f + * @retval: + * the return value of f + */ + unsafe fn with_retval(&self, f: impl FnOnce() -> T) -> T{ + let old_frame = satp::read().frame(); + let new_frame = self.p2_frame.clone(); + debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); + if old_frame != new_frame { + satp::set(satp::Mode::Sv32, 0, new_frame); + sfence_vma_all(); + } + let target = f(); + debug!("switch table {:x?} -> {:x?}", new_frame, old_frame); + if old_frame != new_frame { + satp::set(satp::Mode::Sv32, 0, old_frame); + sfence_vma_all(); + } + target + } + + /* + * @brief: + * get the token of self, the token is self's pagetable frame's starting physical address + * @retval: + * self token + */ fn token(&self) -> usize { self.p2_frame.number() | (1 << 31) // as satp } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 685eeea..28ef150 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -69,8 +69,8 @@ pub fn kmain() -> ! { // the test is not supported in riscv32(maybe) //thread::test::local_key(); //thread::test::unpack(); - sync::test::philosopher_using_mutex(); - sync::test::philosopher_using_monitor(); + //sync::test::philosopher_using_mutex(); + //sync::test::philosopher_using_monitor(); //sync::mpsc::test::test_all(); // come into shell diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 14745b3..1badead 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -7,6 +7,8 @@ use ucore_memory::{*, paging::PageTable}; use ucore_memory::cow::CowExt; pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, Stack}; use ucore_memory::swap::*; +use alloc::collections::VecDeque; +use process::processor; pub type MemorySet = MemorySet_; @@ -22,6 +24,7 @@ lazy_static! { pub static ref FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAlloc::default()); } + lazy_static! { static ref ACTIVE_TABLE: Mutex> = Mutex::new(unsafe { CowExt::new(ActivePageTable::new()) @@ -33,7 +36,7 @@ pub fn active_table() -> MutexGuard<'static, CowExt> { ACTIVE_TABLE.lock() } -// Page table for swpa in and out +// Page table for swap in and out lazy_static!{ static ref ACTIVE_TABLE_SWAP: Mutex> = Mutex::new(unsafe{SwapExt::new(ActivePageTable::new(), fifo::FifoSwapManager::default(), mock_swapper::MockSwapper::default())}); @@ -54,7 +57,7 @@ pub fn alloc_frame() -> Option { let ret = FRAME_ALLOCATOR.lock().alloc().map(|id| id * PAGE_SIZE + MEMORY_OFFSET); trace!("Allocate frame: {:x?}", ret); //do we need : unsafe { ACTIVE_TABLE_SWAP.force_unlock(); } ??? - Some(ret.unwrap_or_else(|| active_table_swap().swap_out_any().ok().unwrap())) + Some(ret.unwrap_or_else(|| active_table_swap().swap_out_any::().ok().unwrap())) } pub fn dealloc_frame(target: usize) { @@ -88,8 +91,11 @@ pub fn page_fault_handler(addr: usize) -> bool { return true; } // handle the swap in/out + info!("start handling swap in/out page fault"); unsafe { ACTIVE_TABLE_SWAP.force_unlock(); } - if active_table_swap().page_fault_handler(addr, || alloc_frame().unwrap()){ + let mut temp_proc = processor(); + let pt = temp_proc.current_context_mut().get_memory_set_mut().get_page_table_mut(); + if active_table_swap().page_fault_handler(pt as *mut InactivePageTable0, addr, || alloc_frame().unwrap()){ return true; } false diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index 0237307..e289efb 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -1,8 +1,9 @@ use arch::interrupt::{TrapFrame, Context as ArchContext}; -use memory::{MemoryArea, MemoryAttr, MemorySet, active_table_swap}; +use memory::{MemoryArea, MemoryAttr, MemorySet, active_table_swap, alloc_frame}; use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use core::fmt::{Debug, Error, Formatter}; use ucore_memory::{Page}; +use ::memory::{InactivePageTable0}; pub struct Context { arch: ArchContext, @@ -106,14 +107,9 @@ impl Context { }); } + //set the user Memory pages in the memory set swappable - for area in memory_set.iter(){ - for page in Page::range_of(area.get_start_addr(), area.get_end_addr()) { - let addr = page.start_address(); - active_table_swap().set_swappable(addr); - } - } - info!("finish setting memory swappable."); + memory_set_map_swappable(&mut memory_set); Context { arch: unsafe { @@ -127,7 +123,7 @@ impl Context { /// Fork pub fn fork(&self, tf: &TrapFrame) -> Self { // Clone memory set, make a new page table - let memory_set = self.memory_set.clone(); + let mut memory_set = self.memory_set.clone(); // Copy data to temp space use alloc::vec::Vec; @@ -143,12 +139,39 @@ impl Context { } }); } + // map the memory set swappable + memory_set_map_swappable(&mut memory_set); Context { arch: unsafe { ArchContext::new_fork(tf, memory_set.kstack_top(), memory_set.token()) }, memory_set, } } + + pub fn get_memory_set_mut(&mut self) -> &mut MemorySet { + &mut self.memory_set + } + +} + +impl Drop for Context{ + fn drop(&mut self){ + //set the user Memory pages in the memory set unswappable + let Self {ref mut arch, ref mut memory_set} = self; + let pt = { + memory_set.get_page_table_mut() as *mut InactivePageTable0 + }; + for area in memory_set.iter(){ + for page in Page::range_of(area.get_start_addr(), area.get_end_addr()) { + let addr = page.start_address(); + unsafe { + active_table_swap().remove_from_swappable(pt, addr, || alloc_frame().unwrap()); + } + } + } + info!("Finishing setting pages unswappable"); + + } } impl Debug for Context { @@ -186,4 +209,23 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { // TODO: handle readonly if elf_flags.is_execute() { flags = flags.execute(); } flags +} + +/* +* @param: +* memory_set: the target MemorySet to set swappable +* @brief: +* map the memory area in the memory_set swappalbe, specially for the user process +*/ +fn memory_set_map_swappable(memory_set: &mut MemorySet){ + let pt = unsafe { + memory_set.get_page_table_mut() as *mut InactivePageTable0 + }; + for area in memory_set.iter(){ + for page in Page::range_of(area.get_start_addr(), area.get_end_addr()) { + let addr = page.start_address(); + active_table_swap().set_swappable(pt, addr); + } + } + info!("Finishing setting pages swappable"); } \ No newline at end of file