Basic swap framework, temporarily disable SwapManagers

master
WangRunji 7 years ago
parent cd020b97f9
commit a7a34835d5

@ -78,12 +78,12 @@ impl<T: PageTable> CowExt<T> {
}
use core::mem::uninitialized;
let mut temp_data: [u8; PAGE_SIZE] = unsafe { uninitialized() };
self.read_page(addr, &mut temp_data[..]);
temp_data[..].copy_from_slice(self.get_page_slice_mut(addr));
self.unmap_shared(addr);
self.map(addr, alloc_frame());
self.write_page(addr, &temp_data[..]);
self.get_page_slice_mut(addr).copy_from_slice(&temp_data[..]);
true
}
}

@ -5,7 +5,7 @@ extern crate alloc;
pub mod paging;
pub mod cow;
//pub mod swap;
pub mod swap;
type VirtAddr = usize;
type PhysAddr = usize;

@ -19,6 +19,7 @@ pub struct MockEntry {
dirty: bool,
writable_shared: bool,
readonly_shared: bool,
swapped: bool,
}
impl Entry for MockEntry {
@ -32,7 +33,7 @@ impl Entry for MockEntry {
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 }
fn set_target(&mut self, target: usize) { self.target = target; }
fn writable_shared(&self) -> bool { self.writable_shared }
fn readonly_shared(&self) -> bool { self.readonly_shared }
fn set_shared(&mut self, writable: bool) {
@ -43,7 +44,8 @@ impl Entry for MockEntry {
self.writable_shared = false;
self.readonly_shared = false;
}
fn swapped(&self) -> bool { self.swapped }
fn set_swapped(&mut self, value: bool) { self.swapped = value; }
fn user(&self) -> bool { unimplemented!() }
fn set_user(&mut self, value: bool) { unimplemented!() }
fn execute(&self) -> bool { unimplemented!() }
@ -71,15 +73,11 @@ impl PageTable for MockPageTable {
fn get_entry(&mut self, addr: VirtAddr) -> &mut <Self as PageTable>::Entry {
&mut self.entries[addr / PAGE_SIZE]
}
fn read_page(&mut self, addr: usize, data: &mut [u8]) {
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
self._read(addr);
let pa = self.translate(addr) & !(PAGE_SIZE - 1);
data.copy_from_slice(&self.data[pa..pa + PAGE_SIZE]);
}
fn write_page(&mut self, addr: usize, data: &[u8]) {
self._write(addr);
let pa = self.translate(addr) & !(PAGE_SIZE - 1);
self.data[pa..pa + PAGE_SIZE].copy_from_slice(data);
let data = unsafe{ &mut *(&mut self.data as *mut [u8; PAGE_SIZE * PAGE_COUNT])};
&mut data[pa..pa + PAGE_SIZE]
}
fn read(&mut self, addr: usize) -> u8 {
self._read(addr);

@ -15,8 +15,7 @@ pub trait PageTable {
fn unmap(&mut self, addr: VirtAddr);
fn get_entry(&mut self, addr: VirtAddr) -> &mut Self::Entry;
// For testing with mock
fn read_page(&mut self, addr: VirtAddr, data: &mut [u8]);
fn write_page(&mut self, addr: VirtAddr, data: &[u8]);
fn get_page_slice_mut<'a,'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8];
fn read(&mut self, addr: VirtAddr) -> u8;
fn write(&mut self, addr: VirtAddr, data: u8);
}
@ -42,6 +41,7 @@ pub trait Entry {
fn set_present(&mut self, value: bool);
fn target(&self) -> PhysAddr;
fn set_target(&mut self, target: PhysAddr);
// For Copy-on-write extension
fn writable_shared(&self) -> bool;
@ -49,6 +49,10 @@ pub trait Entry {
fn set_shared(&mut self, writable: bool);
fn clear_shared(&mut self);
// For Swap extension
fn swapped(&self) -> bool;
fn set_swapped(&mut self, value: bool);
fn user(&self) -> bool;
fn set_user(&mut self, value: bool);
fn execute(&self) -> bool;

@ -1,27 +1,35 @@
use super::Swapper;
use alloc::btree_map::BTreeMap;
use core::mem::uninitialized;
const PAGE_SIZE: usize = 4096;
#[derive(Default)]
pub struct MockSwapper {
map: BTreeMap<usize, [u8; 4096]>,
map: BTreeMap<usize, [u8; PAGE_SIZE]>,
}
impl Swapper for MockSwapper {
fn swap_out(&mut self, data: &[u8; 4096]) -> Result<usize, ()> {
fn swap_out(&mut self, data: &[u8]) -> Result<usize, ()> {
let id = self.alloc_id();
self.map.insert(id, data.clone());
let mut slice: [u8; PAGE_SIZE] = unsafe{ uninitialized() };
slice.copy_from_slice(data);
self.map.insert(id, slice);
Ok(id)
}
fn swap_update(&mut self, token: usize, data: &[u8; 4096]) -> Result<(), ()> {
fn swap_update(&mut self, token: usize, data: &[u8]) -> Result<(), ()> {
if !self.map.contains_key(&token) {
return Err(());
}
self.map.insert(token, data.clone());
let mut slice: [u8; PAGE_SIZE] = unsafe{ uninitialized() };
slice.copy_from_slice(data);
self.map.insert(token, slice);
Ok(())
}
fn swap_in(&mut self, token: usize, data: &mut [u8; 4096]) -> Result<(), ()> {
fn swap_in(&mut self, token: usize, data: &mut [u8]) -> Result<(), ()> {
match self.map.remove(&token) {
Some(d) => *data = d,
Some(d) => data.copy_from_slice(d.as_ref()),
None => return Err(()),
}
Ok(())
@ -29,9 +37,6 @@ impl Swapper for MockSwapper {
}
impl MockSwapper {
pub fn new() -> Self {
MockSwapper {map: BTreeMap::new()}
}
fn alloc_id(&self) -> usize {
(0 .. 100usize).find(|i| !self.map.contains_key(i)).unwrap()
}
@ -40,7 +45,6 @@ impl MockSwapper {
#[cfg(test)]
mod test {
use super::*;
use core::mem::uninitialized;
fn assert_data_eq(data1: &[u8; 4096], data2: &[u8; 4096]) {
for (&a, &b) in data2.iter().zip(data1.iter()) {
@ -50,7 +54,7 @@ mod test {
#[test]
fn swap_out_in() {
let mut swapper = MockSwapper::new();
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let token = swapper.swap_out(&data1).unwrap();
@ -60,7 +64,7 @@ mod test {
#[test]
fn swap_update() {
let mut swapper = MockSwapper::new();
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let data2: [u8; 4096] = unsafe{ uninitialized() };
@ -72,7 +76,7 @@ mod test {
#[test]
fn invalid_token() {
let mut swapper = MockSwapper::new();
let mut swapper = MockSwapper::default();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
assert_eq!(swapper.swap_in(0, &mut data), Err(()));
}

@ -1,13 +1,16 @@
pub use self::fifo::FifoSwapManager;
pub use self::enhanced_clock::EnhancedClockSwapManager;
use super::*;
use super::paging::PageTable;
use super::paging::*;
use core::ops::{Deref, DerefMut};
//pub use self::fifo::FifoSwapManager;
//pub use self::enhanced_clock::EnhancedClockSwapManager;
mod fifo;
mod enhanced_clock;
//mod fifo;
//mod enhanced_clock;
#[cfg(test)]
mod mock_swapper;
/// Manage all swappable pages, decide which to swap out
pub trait SwapManager {
/// Called when tick interrupt occured
fn tick(&mut self);
@ -20,11 +23,99 @@ pub trait SwapManager {
}
pub trait Swapper {
fn swap_out(&mut self, data: &[u8; 4096]) -> Result<usize, ()>;
fn swap_update(&mut self, token: usize, data: &[u8; 4096]) -> Result<(), ()>;
fn swap_in(&mut self, token: usize, data: &mut [u8; 4096]) -> Result<(), ()>;
/// Allocate space on device and write data to it.
/// Return a token indicating the location.
fn swap_out(&mut self, data: &[u8]) -> Result<usize, ()>;
/// Update data on device.
fn swap_update(&mut self, token: usize, data: &[u8]) -> Result<(), ()>;
/// Recover data from device and deallocate the space.
fn swap_in(&mut self, token: usize, data: &mut [u8]) -> Result<(), ()>;
}
/// Wrapper for page table, supporting swap functions
struct SwapExt<T: PageTable, M: SwapManager, S: Swapper> {
page_table: T,
swap_manager: M,
swapper: S,
}
impl<T: PageTable, M: SwapManager, S: Swapper> SwapExt<T, M, S> {
pub fn new(page_table: T, swap_manager: M, swapper: S) -> Self {
SwapExt {
page_table,
swap_manager,
swapper,
}
}
/// Swap out any one of the swapped pages, return the released PhysAddr.
pub fn swap_out_any(&mut self) -> Result<PhysAddr, SwapError> {
match self.swap_manager.pop() {
None => Err(SwapError::NoSwapped),
Some(addr) => self.swap_out(addr),
}
}
/// Swap out page of `addr`, return the origin map target.
fn swap_out(&mut self, addr: VirtAddr) -> Result<PhysAddr, SwapError> {
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)
}
/// Map page of `addr` to `target`, then swap in the data.
fn swap_in(&mut self, addr: VirtAddr, target: PhysAddr) -> Result<(), SwapError> {
let token = {
let entry = self.page_table.get_entry(addr);
if !entry.swapped() {
return Err(SwapError::NotSwapped);
}
let token = entry.target() / PAGE_SIZE;
entry.set_target(target);
entry.set_swapped(false);
entry.set_present(true);
entry.update();
token
};
let data = self.page_table.get_page_slice_mut(addr);
self.swapper.swap_in(token, data).map_err(|_| SwapError::IOError)?;
Ok(())
}
pub fn page_fault_handler(&mut self, addr: VirtAddr, alloc_frame: impl FnOnce() -> PhysAddr) -> bool {
{
let entry = self.page_table.get_entry(addr);
if !entry.swapped() {
return false;
}
}
self.swap_in(addr, alloc_frame()).ok().unwrap();
true
}
}
pub enum SwapError {
AlreadySwapped,
NotSwapped,
NoSwapped,
IOError,
}
impl<T: PageTable, M: SwapManager, S: Swapper> Deref for SwapExt<T, M, S> {
type Target = T;
fn deref(&self) -> &<Self as Deref>::Target {
&self.page_table
}
}
pub trait SwappablePageTable: PageTable {
fn swap_out(&mut self, addr: VirtAddr) -> Result<(), ()>;
impl<T: PageTable, M: SwapManager, S: Swapper> DerefMut for SwapExt<T, M, S> {
fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
&mut self.page_table
}
}

@ -58,16 +58,9 @@ impl PageTable for ActivePageTable {
unsafe { &mut *(entry_addr as *mut PageEntry) }
}
fn read_page(&mut self, addr: usize, data: &mut [u8]) {
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
use core::slice;
let mem = unsafe { slice::from_raw_parts((addr & !0xfffusize) as *const u8, 4096) };
data.copy_from_slice(mem);
}
fn write_page(&mut self, addr: usize, data: &[u8]) {
use core::slice;
let mem = unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, 4096) };
mem.copy_from_slice(data);
unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, PAGE_SIZE) }
}
fn read(&mut self, addr: usize) -> u8 {
@ -119,6 +112,10 @@ impl Entry for PageEntry {
fn set_writable(&mut self, value: bool) { self.as_flags().set(EF::WRITABLE, value); }
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::PRESENT, value); }
fn target(&self) -> usize { self.0.addr().as_u64() as usize }
fn set_target(&mut self, target: usize) {
let flags = self.0.flags();
self.0.set_addr(PhysAddr::new(target as u64), flags);
}
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::BIT_10) }
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::BIT_9) }
fn set_shared(&mut self, writable: bool) {
@ -127,6 +124,8 @@ impl Entry for PageEntry {
flags.set(EF::BIT_9, !writable);
}
fn clear_shared(&mut self) { self.as_flags().remove(EF::BIT_9 | EF::BIT_10); }
fn swapped(&self) -> bool { self.0.flags().contains(EF::BIT_11) }
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::BIT_11, value); }
fn user(&self) -> bool { self.0.flags().contains(EF::USER_ACCESSIBLE) }
fn set_user(&mut self, value: bool) {
self.as_flags().set(EF::USER_ACCESSIBLE, value);

@ -14,7 +14,7 @@ mod memory_set;
mod stack_allocator;
mod address;
const PAGE_SIZE: usize = 1 << 12;
pub const PAGE_SIZE: usize = 1 << 12;
lazy_static! {
static ref FRAME_ALLOCATOR: Mutex<BitAlloc64K> = Mutex::new(BitAlloc64K::default());

Loading…
Cancel
Save