parent
88e1055eed
commit
a25c8132fe
@ -0,0 +1,108 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Delay mapping a page to an area of a file.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct File<F, T> {
|
||||||
|
pub file: F,
|
||||||
|
pub mem_start: usize,
|
||||||
|
pub file_start: usize,
|
||||||
|
pub file_end: usize,
|
||||||
|
pub allocator: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Read: Clone + Send + Sync + 'static {
|
||||||
|
fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Read, T: FrameAllocator> MemoryHandler for File<F, T> {
|
||||||
|
fn box_clone(&self) -> Box<MemoryHandler> {
|
||||||
|
Box::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self, pt: &mut PageTable, addr: usize, attr: &MemoryAttr) {
|
||||||
|
let entry = pt.map(addr, 0);
|
||||||
|
entry.set_present(false);
|
||||||
|
attr.apply(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, pt: &mut PageTable, addr: usize) {
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
if entry.present() {
|
||||||
|
self.allocator.dealloc(entry.target());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageTable::unmap requires page to be present
|
||||||
|
entry.set_present(true);
|
||||||
|
pt.unmap(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_map(
|
||||||
|
&self,
|
||||||
|
pt: &mut PageTable,
|
||||||
|
with: &Fn(&mut FnMut()),
|
||||||
|
addr: usize,
|
||||||
|
attr: &MemoryAttr,
|
||||||
|
) {
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
if entry.present() && !attr.readonly {
|
||||||
|
// eager map and copy data
|
||||||
|
let data = Vec::from(pt.get_page_slice_mut(addr));
|
||||||
|
with(&mut || {
|
||||||
|
let target = self.allocator.alloc().expect("failed to alloc frame");
|
||||||
|
let target_data = pt.get_page_slice_mut(addr);
|
||||||
|
let entry = pt.map(addr, target);
|
||||||
|
target_data.copy_from_slice(&data);
|
||||||
|
attr.apply(entry);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// delay map
|
||||||
|
with(&mut || self.map(pt, addr, attr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_page_fault(&self, pt: &mut PageTable, addr: usize) -> bool {
|
||||||
|
let addr = addr & !(PAGE_SIZE - 1);
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
if entry.present() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let frame = self.allocator.alloc().expect("failed to alloc frame");
|
||||||
|
entry.set_target(frame);
|
||||||
|
entry.set_present(true);
|
||||||
|
let writable = entry.writable();
|
||||||
|
entry.set_writable(true);
|
||||||
|
entry.update();
|
||||||
|
|
||||||
|
self.fill_data(pt, addr);
|
||||||
|
|
||||||
|
let entry = pt.get_entry(addr).expect("failed to get entry");
|
||||||
|
entry.set_writable(writable);
|
||||||
|
entry.update();
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: Read, T: FrameAllocator> File<F, T> {
|
||||||
|
fn fill_data(&self, pt: &mut PageTable, addr: VirtAddr) {
|
||||||
|
let data = pt.get_page_slice_mut(addr);
|
||||||
|
let file_offset = addr + self.file_start - self.mem_start;
|
||||||
|
let read_size = (self.file_end as isize - file_offset as isize)
|
||||||
|
.min(PAGE_SIZE as isize)
|
||||||
|
.max(0) as usize;
|
||||||
|
let read_size = self.file.read_at(file_offset, &mut data[..read_size]);
|
||||||
|
if read_size != PAGE_SIZE {
|
||||||
|
data[read_size..].iter_mut().for_each(|x| *x = 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, T> Debug for File<F, T> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||||
|
f.debug_struct("FileHandler")
|
||||||
|
.field("mem_start", &self.mem_start)
|
||||||
|
.field("file_start", &self.file_start)
|
||||||
|
.field("file_end", &self.file_end)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue