diff --git a/src/context/memory.rs b/src/context/memory.rs index c3272e25aedfdba5f5edd9ddbe2b2ceb3687c95f..0f037b1bd66c4d5deae7f47a6d607d9373296d42 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -18,6 +18,7 @@ pub struct Grant { size: usize, flags: EntryFlags, mapped: bool, + owned: bool, //TODO: This is probably a very heavy way to keep track of fmap'd files, perhaps move to the context? pub desc_opt: Option<FileDescriptor>, } @@ -43,6 +44,7 @@ impl Grant { size, flags, mapped: true, + owned: false, desc_opt: None, } } @@ -66,6 +68,7 @@ impl Grant { size, flags, mapped: true, + owned: true, desc_opt: None, } } @@ -101,10 +104,95 @@ impl Grant { size, flags, mapped: true, + owned: false, desc_opt, } } + /// This function should only be used in clone! + pub fn secret_clone(&self, new_start: VirtualAddress) -> Grant { + assert!(self.mapped); + + let mut active_table = unsafe { ActivePageTable::new() }; + + let mut flush_all = MapperFlushAll::new(); + + let start_page = Page::containing_address(self.start); + let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + //TODO: One function to do both? + let flags = active_table.translate_page_flags(page).expect("grant references unmapped memory"); + let frame = active_table.translate_page(page).expect("grant references unmapped memory"); + + let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get())); + if self.owned { + let result = active_table.map(new_page, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE); + flush_all.consume(result); + } else { + let result = active_table.map_to(new_page, frame, flags); + flush_all.consume(result); + } + } + + flush_all.flush(&mut active_table); + + if self.owned { + unsafe { + intrinsics::copy(self.start.get() as *const u8, new_start.get() as *mut u8, self.size); + } + + let mut flush_all = MapperFlushAll::new(); + + for page in Page::range_inclusive(start_page, end_page) { + //TODO: One function to do both? + let flags = active_table.translate_page_flags(page).expect("grant references unmapped memory"); + + let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get())); + let result = active_table.remap(new_page, flags); + flush_all.consume(result); + } + + flush_all.flush(&mut active_table); + } + + Grant { + start: new_start, + size: self.size, + flags: self.flags, + mapped: true, + owned: self.owned, + desc_opt: self.desc_opt.clone() + } + } + + pub fn move_to(&mut self, new_start: VirtualAddress, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) { + assert!(self.mapped); + + let mut active_table = unsafe { ActivePageTable::new() }; + + let mut flush_all = MapperFlushAll::new(); + + let start_page = Page::containing_address(self.start); + let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + //TODO: One function to do both? + let flags = active_table.translate_page_flags(page).expect("grant references unmapped memory"); + let (result, frame) = active_table.unmap_return(page, false); + flush_all.consume(result); + + active_table.with(new_table, temporary_page, |mapper| { + let new_page = Page::containing_address(VirtualAddress::new(page.start_address().get() - self.start.get() + new_start.get())); + let result = mapper.map_to(new_page, frame, flags); + // Ignore result due to mapping on inactive table + unsafe { result.ignore(); } + }); + } + + flush_all.flush(&mut active_table); + + self.start = new_start; + } + pub fn start_address(&self) -> VirtualAddress { self.start } @@ -117,9 +205,17 @@ impl Grant { self.flags } + pub unsafe fn set_mapped(&mut self, mapped: bool) { + self.mapped = mapped; + } + pub fn unmap(mut self) { assert!(self.mapped); + if self.owned { + println!("Grant::unmap: leaked {:?}", self); + } + let mut active_table = unsafe { ActivePageTable::new() }; let mut flush_all = MapperFlushAll::new(); @@ -144,6 +240,10 @@ impl Grant { pub fn unmap_inactive(mut self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) { assert!(self.mapped); + if self.owned { + println!("Grant::unmap_inactive: leaked {:?}", self); + } + let mut active_table = unsafe { ActivePageTable::new() }; active_table.with(new_table, temporary_page, |mapper| {