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