From aa109498f1c7493f7f02aff13b2fb816d9494ca4 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Wed, 20 Jun 2018 16:33:03 +0800 Subject: [PATCH] Clear memory crate, redefine PageTable interface, reimplement MockPageTable. --- crate/memory/src/lib.rs | 5 +- crate/memory/src/memory_set.rs | 89 ----------- crate/memory/src/paging/mock_page_table.rs | 146 ++++++++++++++++++ crate/memory/src/paging/mod.rs | 28 +++- .../src/paging/page_table/mock_page_table.rs | 130 ---------------- crate/memory/src/paging/page_table/mod.rs | 13 -- crate/memory/src/physical/frame.rs | 33 ---- .../src/physical/frame_allocator/mod.rs | 11 -- crate/memory/src/physical/mod.rs | 9 -- crate/memory/src/physical/physaddr.rs | 50 ------ crate/memory/src/swap/enhanced_clock.rs | 10 +- 11 files changed, 178 insertions(+), 346 deletions(-) delete mode 100644 crate/memory/src/memory_set.rs create mode 100644 crate/memory/src/paging/mock_page_table.rs delete mode 100644 crate/memory/src/paging/page_table/mock_page_table.rs delete mode 100644 crate/memory/src/paging/page_table/mod.rs delete mode 100644 crate/memory/src/physical/frame.rs delete mode 100644 crate/memory/src/physical/frame_allocator/mod.rs delete mode 100644 crate/memory/src/physical/mod.rs delete mode 100644 crate/memory/src/physical/physaddr.rs diff --git a/crate/memory/src/lib.rs b/crate/memory/src/lib.rs index e9dc3de..40a15e0 100644 --- a/crate/memory/src/lib.rs +++ b/crate/memory/src/lib.rs @@ -3,10 +3,9 @@ extern crate alloc; -pub mod physical; pub mod paging; -pub mod memory_set; -pub mod swap; +//pub mod swap; type VirtAddr = usize; +type PhysAddr = usize; const PAGE_SIZE: usize = 4096; \ No newline at end of file diff --git a/crate/memory/src/memory_set.rs b/crate/memory/src/memory_set.rs deleted file mode 100644 index 7b2705f..0000000 --- a/crate/memory/src/memory_set.rs +++ /dev/null @@ -1,89 +0,0 @@ -use alloc::vec::Vec; - -type Addr = usize; - -/// 一片连续内存空间,有相同的访问权限 -/// 对应ucore中 `vma_struct` -#[derive(Debug, Eq, PartialEq)] -pub struct MemoryArea { - pub start_addr: Addr, - pub end_addr: Addr, - pub flags: u32, - pub name: &'static str, -} - -impl MemoryArea { - pub fn contains(&self, addr: Addr) -> bool { - addr >= self.start_addr && addr < self.end_addr - } - fn is_overlap_with(&self, other: &MemoryArea) -> bool { - !(self.end_addr <= other.start_addr || self.start_addr >= other.end_addr) - } -} - -/// 内存空间集合,包含若干段连续空间 -/// 对应ucore中 `mm_struct` -#[derive(Debug)] -pub struct MemorySet { - areas: Vec, -} - -impl MemorySet { - pub fn new() -> Self { - MemorySet { areas: Vec::::new() } - } - pub fn find_area(&self, addr: Addr) -> Option<&MemoryArea> { - self.areas.iter().find(|area| area.contains(addr)) - } - pub fn push(&mut self, area: MemoryArea) { - assert!(area.start_addr <= area.end_addr, "invalid memory area"); - if self.areas.iter() - .find(|other| area.is_overlap_with(other)) - .is_some() { - panic!("memory area overlap"); - } - self.areas.push(area); - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn push_and_find() { - let mut ms = MemorySet::new(); - ms.push(MemoryArea { - start_addr: 0x0, - end_addr: 0x8, - flags: 0x0, - name: "code", - }); - ms.push(MemoryArea { - start_addr: 0x8, - end_addr: 0x10, - flags: 0x1, - name: "data", - }); - assert_eq!(ms.find_area(0x6).unwrap().name, "code"); - assert_eq!(ms.find_area(0x11), None); - } - - #[test] - #[should_panic] - fn push_overlap() { - let mut ms = MemorySet::new(); - ms.push(MemoryArea { - start_addr: 0x0, - end_addr: 0x8, - flags: 0x0, - name: "code", - }); - ms.push(MemoryArea { - start_addr: 0x4, - end_addr: 0x10, - flags: 0x1, - name: "data", - }); - } -} diff --git a/crate/memory/src/paging/mock_page_table.rs b/crate/memory/src/paging/mock_page_table.rs new file mode 100644 index 0000000..b786e0f --- /dev/null +++ b/crate/memory/src/paging/mock_page_table.rs @@ -0,0 +1,146 @@ +use alloc::boxed::Box; +use super::*; + +const PAGE_COUNT: usize = 16; +const PAGE_SIZE: usize = 4096; + +pub struct MockPageTable { + entries: [MockEntry; PAGE_COUNT], + data: [u8; PAGE_SIZE * PAGE_COUNT], + page_fault_handler: Option, +} + +#[derive(Default, Copy, Clone)] +pub struct MockEntry { + target: PhysAddr, + present: bool, + writable: bool, + accessed: bool, + dirty: bool, +} + +impl Entry for MockEntry { + fn accessed(&self) -> bool { self.accessed } + fn dirty(&self) -> bool { self.dirty } + fn writable(&self) -> bool { self.writable } + fn present(&self) -> bool { self.present } + fn clear_accessed(&mut self) { self.accessed = false; } + fn clear_dirty(&mut self) { self.dirty = false; } + fn set_writable(&mut self, value: bool) { self.writable = value; } + fn set_present(&mut self, value: bool) { self.present = value; } + fn target(&self) -> usize { self.target } +} + +type PageFaultHandler = Box; + +impl PageTable for MockPageTable { + type Entry = MockEntry; + + /// Map a page, return false if no more space + fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry { + let entry = &mut self.entries[addr / PAGE_SIZE]; + assert!(!entry.present); + entry.present = true; + entry.target = target & !(PAGE_SIZE - 1); + entry + } + fn unmap(&mut self, addr: VirtAddr) { + let entry = &mut self.entries[addr / PAGE_SIZE]; + assert!(entry.present); + entry.present = false; + } + + fn get_entry(&mut self, addr: VirtAddr) -> &mut ::Entry { + &mut self.entries[addr / PAGE_SIZE] + } +} + +impl MockPageTable { + pub fn new() -> Self { + use core::mem::uninitialized; + MockPageTable { + entries: [MockEntry::default(); PAGE_COUNT], + data: unsafe { uninitialized() }, + page_fault_handler: None, + } + } + pub fn set_handler(&mut self, page_fault_handler: PageFaultHandler) { + self.page_fault_handler = Some(page_fault_handler); + } + fn trigger_page_fault(&mut self, addr: VirtAddr) { + // In order to call the handler with &mut self as an argument + // We have to first take the handler out of self, finally put it back + let mut handler = self.page_fault_handler.take().unwrap(); + handler(self, addr); + self.page_fault_handler = Some(handler); + } + fn translate(&self, addr: VirtAddr) -> PhysAddr { + let entry = &self.entries[addr / PAGE_SIZE]; + assert!(entry.present); + (entry.target & !(PAGE_SIZE - 1)) | (addr & (PAGE_SIZE - 1)) + } + /// Read memory, mark accessed, trigger page fault if not present + pub fn read(&mut self, addr: VirtAddr) -> u8 { + while !self.entries[addr / PAGE_SIZE].present { + self.trigger_page_fault(addr); + } + self.entries[addr / PAGE_SIZE].accessed = true; + self.data[self.translate(addr)] + } + /// Write memory, mark accessed and dirty, trigger page fault if not present + pub fn write(&mut self, addr: VirtAddr, data: u8) { + while !(self.entries[addr / PAGE_SIZE].present && self.entries[addr / PAGE_SIZE].writable) { + self.trigger_page_fault(addr); + } + self.entries[addr / PAGE_SIZE].accessed = true; + self.entries[addr / PAGE_SIZE].dirty = true; + self.data[self.translate(addr)] = data; + } +} + +#[cfg(test)] +mod test { + use super::*; + use alloc::arc::Arc; + use core::cell::RefCell; + + #[test] + fn test() { + let page_fault_count = Arc::new(RefCell::new(0usize)); + + let mut pt = MockPageTable::new(); + pt.set_handler(Box::new({ + let page_fault_count1 = page_fault_count.clone(); + move |pt: &mut MockPageTable, addr: VirtAddr| { + *page_fault_count1.borrow_mut() += 1; + pt.map(addr, addr).set_writable(true); + } + })); + + pt.map(0, 0); + pt.read(0); + assert_eq!(*page_fault_count.borrow(), 0); + assert!(pt.get_entry(0).accessed()); + assert!(!pt.get_entry(0).dirty()); + + pt.get_entry(0).clear_accessed(); + assert!(!pt.get_entry(0).accessed()); + + pt.read(1); + assert_eq!(*page_fault_count.borrow(), 0); + assert!(pt.get_entry(0).accessed()); + + pt.write(0x1000, 0xff); + assert_eq!(*page_fault_count.borrow(), 1); + assert!(pt.get_entry(0x1000).accessed()); + assert!(pt.get_entry(0x1000).dirty()); + assert_eq!(pt.read(0x1000), 0xff); + + pt.get_entry(0x1000).clear_dirty(); + assert!(!pt.get_entry(0x1000).dirty()); + + pt.unmap(0); + pt.read(0); + assert_eq!(*page_fault_count.borrow(), 2); + } +} \ No newline at end of file diff --git a/crate/memory/src/paging/mod.rs b/crate/memory/src/paging/mod.rs index cd6f6b6..7568d09 100644 --- a/crate/memory/src/paging/mod.rs +++ b/crate/memory/src/paging/mod.rs @@ -1,4 +1,28 @@ -pub use self::page_table::*; use super::*; +pub use self::mock_page_table::MockPageTable; -mod page_table; \ No newline at end of file +mod mock_page_table; + +pub trait PageTable { + type Entry: Entry; + fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry; + fn unmap(&mut self, addr: VirtAddr); + fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry; +} + +pub trait Entry { + fn accessed(&self) -> bool; + // Will be set when accessed + fn dirty(&self) -> bool; + // Will be set when written + fn writable(&self) -> bool; + // Will PageFault when try to write page where writable=0 + fn present(&self) -> bool; // Will PageFault when try to access page where present=0 + + fn clear_accessed(&mut self); + fn clear_dirty(&mut self); + fn set_writable(&mut self, value: bool); + fn set_present(&mut self, value: bool); + + fn target(&self) -> PhysAddr; +} diff --git a/crate/memory/src/paging/page_table/mock_page_table.rs b/crate/memory/src/paging/page_table/mock_page_table.rs deleted file mode 100644 index 85954b8..0000000 --- a/crate/memory/src/paging/page_table/mock_page_table.rs +++ /dev/null @@ -1,130 +0,0 @@ -use alloc::boxed::Box; -use super::*; - -const PAGE_COUNT: usize = 16; -const PAGE_SIZE: usize = 4096; - -pub struct MockPageTable { - mapped: [bool; PAGE_COUNT], - accessed: [bool; PAGE_COUNT], - dirty: [bool; PAGE_COUNT], - data: [u8; PAGE_SIZE * PAGE_COUNT], - page_fault_handler: Option, - capacity: usize, -} - -type PageFaultHandler = Box; - -impl PageTable for MockPageTable { - fn accessed(&self, addr: VirtAddr) -> bool { - self.accessed[addr / PAGE_SIZE] - } - fn dirty(&self, addr: VirtAddr) -> bool { - self.dirty[addr / PAGE_SIZE] - } - fn clear_accessed(&mut self, addr: usize) { - self.accessed[addr / PAGE_SIZE] = false; - } - fn clear_dirty(&mut self, addr: usize) { - self.dirty[addr / PAGE_SIZE] = false; - } - /// Map a page, return false if no more space - fn map(&mut self, addr: VirtAddr) -> bool { - if self.mapped.iter().filter(|&&b| b).count() == self.capacity { - return false; - } - self.mapped[addr / PAGE_SIZE] = true; - true - } - fn unmap(&mut self, addr: VirtAddr) { - self.mapped[addr / PAGE_SIZE] = false; - } -} - -impl MockPageTable { - pub fn new(capacity: usize) -> Self { - use core::mem::uninitialized; - MockPageTable { - mapped: [false; PAGE_COUNT], - accessed: [false; PAGE_COUNT], - dirty: [false; PAGE_COUNT], - data: unsafe{ uninitialized() }, - page_fault_handler: None, - capacity, - } - } - pub fn set_handler(&mut self, page_fault_handler: PageFaultHandler) { - self.page_fault_handler = Some(page_fault_handler); - } - fn trigger_page_fault_if_not_present(&mut self, addr: VirtAddr) { - let page_id = addr / PAGE_SIZE; - while !self.mapped[page_id] { - let self_mut = unsafe{ &mut *(self as *mut Self) }; - (self.page_fault_handler.as_mut().unwrap())(self_mut, addr); - } - } - /// Read memory, mark accessed, trigger page fault if not present - pub fn read(&mut self, addr: VirtAddr) -> u8 { - let page_id = addr / PAGE_SIZE; - self.trigger_page_fault_if_not_present(addr); - self.accessed[page_id] = true; - self.data[addr] - } - /// Write memory, mark accessed and dirty, trigger page fault if not present - pub fn write(&mut self, addr: VirtAddr, data: u8) { - let page_id = addr / PAGE_SIZE; - self.trigger_page_fault_if_not_present(addr); - self.accessed[page_id] = true; - self.dirty[page_id] = true; - self.data[addr] = data; - } -} - -#[cfg(test)] -mod test { - use super::*; - use alloc::arc::Arc; - use core::cell::RefCell; - - #[test] - fn test() { - let page_fault_count = Arc::new(RefCell::new(0usize)); - - let mut pt = MockPageTable::new(2); - pt.set_handler(Box::new({ - let page_fault_count1 = page_fault_count.clone(); - move |pt: &mut MockPageTable, addr: VirtAddr| { - *page_fault_count1.borrow_mut() += 1; - pt.map(addr); - } - })); - - pt.map(0); - pt.read(0); - assert_eq!(*page_fault_count.borrow(), 0); - assert!(pt.accessed(0)); - assert!(!pt.dirty(0)); - - pt.clear_accessed(0); - assert!(!pt.accessed(0)); - - pt.read(1); - assert_eq!(*page_fault_count.borrow(), 0); - assert!(pt.accessed(0)); - - pt.write(0x1000, 0xff); - assert_eq!(*page_fault_count.borrow(), 1); - assert!(pt.accessed(0x1000)); - assert!(pt.dirty(0x1000)); - assert_eq!(pt.read(0x1000), 0xff); - - pt.clear_dirty(0x1000); - assert!(!pt.dirty(0x1000)); - - assert_eq!(pt.map(0x2000), false); - - pt.unmap(0); - pt.read(0); - assert_eq!(*page_fault_count.borrow(), 2); - } -} \ No newline at end of file diff --git a/crate/memory/src/paging/page_table/mod.rs b/crate/memory/src/paging/page_table/mod.rs deleted file mode 100644 index 8e1752d..0000000 --- a/crate/memory/src/paging/page_table/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::*; -pub use self::mock_page_table::MockPageTable; - -mod mock_page_table; - -pub trait PageTable { - fn accessed(&self, addr: VirtAddr) -> bool; - fn dirty(&self, addr: VirtAddr) -> bool; - fn clear_accessed(&mut self, addr: VirtAddr); - fn clear_dirty(&mut self, addr: VirtAddr); - fn map(&mut self, addr: VirtAddr) -> bool; - fn unmap(&mut self, addr: VirtAddr); -} \ No newline at end of file diff --git a/crate/memory/src/physical/frame.rs b/crate/memory/src/physical/frame.rs deleted file mode 100644 index d88b1a1..0000000 --- a/crate/memory/src/physical/frame.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::*; - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Frame { - number: usize, -} - -impl Frame { - pub fn containing_address(address: PhysAddr) -> Frame { - Frame{ number: address.get() as usize / PAGE_SIZE } - } - //TODO: Set private - pub fn start_address(&self) -> PhysAddr { - PhysAddr::new((self.number * PAGE_SIZE) as u64) - } - - pub fn clone(&self) -> Frame { - Frame { number: self.number } - } - //TODO: Set private -// pub fn range_inclusive(start: Frame, end: Frame) -> FrameIter { -// FrameIter { -// start: start, -// end: end, -// } -// } -} - -impl Drop for Frame { - fn drop(&mut self) { - panic!("frame must be deallocate"); - } -} diff --git a/crate/memory/src/physical/frame_allocator/mod.rs b/crate/memory/src/physical/frame_allocator/mod.rs deleted file mode 100644 index 80c508d..0000000 --- a/crate/memory/src/physical/frame_allocator/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -use super::*; - -pub trait FrameAllocator { - fn allocate_frame(&mut self) -> Option; - fn deallocate_frame(&mut self, frame: Frame); -} - -pub trait MemoryArea { - fn begin(&self) -> PhysAddr; - fn end(&self) -> PhysAddr; -} \ No newline at end of file diff --git a/crate/memory/src/physical/mod.rs b/crate/memory/src/physical/mod.rs deleted file mode 100644 index 02e9ca4..0000000 --- a/crate/memory/src/physical/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use self::physaddr::PhysAddr; -pub use self::frame::Frame; -pub use self::frame_allocator::FrameAllocator; - -use super::*; - -mod frame; -mod physaddr; -mod frame_allocator; \ No newline at end of file diff --git a/crate/memory/src/physical/physaddr.rs b/crate/memory/src/physical/physaddr.rs deleted file mode 100644 index 3da6871..0000000 --- a/crate/memory/src/physical/physaddr.rs +++ /dev/null @@ -1,50 +0,0 @@ -use core::fmt; - -/// Represents a physical memory address -#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] -pub struct PhysAddr(u64); - -impl PhysAddr { - pub fn new(addr: u64) -> PhysAddr { - PhysAddr(addr) - } - pub fn get(&self) -> u64 { - self.0 - } -} - -impl fmt::Debug for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:#x}", self.0) - } -} - -impl fmt::Binary for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Display for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::LowerHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::Octal for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl fmt::UpperHex for PhysAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} \ No newline at end of file diff --git a/crate/memory/src/swap/enhanced_clock.rs b/crate/memory/src/swap/enhanced_clock.rs index c495d8d..3427995 100644 --- a/crate/memory/src/swap/enhanced_clock.rs +++ b/crate/memory/src/swap/enhanced_clock.rs @@ -29,17 +29,15 @@ impl SwapManager for EnhancedClockSwapManager Option { loop { let addr = self.deque[self.clock_ptr]; - let accessed = self.page_table.accessed(addr); - let dirty = self.page_table.dirty(addr); + let entry = self.page_table.get_entry(addr); - match (accessed, dirty) { + match (entry.accessed(), entry.dirty()) { (true, _) => { - self.page_table.clear_accessed(addr); - + entry.clear_accessed(); }, (false, true) => { if self.page_table.swap_out(addr).is_ok() { - self.page_table.clear_dirty(addr); + entry.clear_dirty(); } }, _ => {