Skip to content

Commit cf41695

Browse files
handle_cow: refactor
Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent 94ec73e commit cf41695

File tree

2 files changed

+61
-30
lines changed

2 files changed

+61
-30
lines changed

src/aero_kernel/src/mem/paging/mapper.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ impl<S: PageSize> MapperFlush<S> {
309309
MapperFlush(page)
310310
}
311311

312+
pub fn ignore(self) {}
313+
312314
/// Flush the page from the TLB to ensure that the newest mapping is used.
313315
#[inline]
314316
pub fn flush(self) {
@@ -1263,7 +1265,8 @@ impl<'a> OffsetPageTable<'a> {
12631265
let last_level_fork = |entry: &mut PageTableEntry, n1: &mut PageTable, i: usize| {
12641266
let mut flags = entry.flags();
12651267

1266-
flags.remove(PageTableFlags::WRITABLE | PageTableFlags::ACCESSED);
1268+
// Setup copy on write page.
1269+
flags.remove(PageTableFlags::WRITABLE);
12671270

12681271
entry.set_flags(flags);
12691272
n1[i].set_frame(entry.frame().unwrap(), flags);

src/aero_kernel/src/userland/vm.rs

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -368,49 +368,77 @@ impl Mapping {
368368
}
369369
}
370370

371+
/// Copies the contents of the `page` page to a newly allocated frame and maps it to
372+
/// the `page` page with the provided `protection` protection flags.
373+
fn map_copied(
374+
offset_table: &mut OffsetPageTable,
375+
page: Page<Size4KiB>,
376+
protection: MMapProt,
377+
) -> Result<(), MapToError<Size4KiB>> {
378+
// Allocate a new frame to hold the contents.
379+
let new_frame: PhysFrame<Size4KiB> = unsafe { FRAME_ALLOCATOR.allocate_frame() }
380+
.expect("map_copied: failed to allocate frame");
381+
382+
let old_slice = unsafe {
383+
let ptr = page.start_address().as_ptr::<u8>();
384+
core::slice::from_raw_parts(ptr, Size4KiB::SIZE as _)
385+
};
386+
387+
let new_slice = unsafe {
388+
let phys = new_frame.start_address().as_u64();
389+
let virt = crate::PHYSICAL_MEMORY_OFFSET + phys;
390+
let ptr = virt.as_mut_ptr::<u8>();
391+
392+
core::slice::from_raw_parts_mut(ptr, Size4KiB::SIZE as _)
393+
};
394+
395+
// Copy the contents from the old frame to the newly allocated frame.
396+
new_slice.copy_from_slice(old_slice);
397+
398+
// Re-map the page to the newly allocated frame and with the provided
399+
// protection flags.
400+
offset_table.unmap(page).unwrap().1.ignore();
401+
402+
// NOTE: We operate on an active page table, so we flush the changes.
403+
unsafe {
404+
offset_table
405+
.map_to(
406+
page,
407+
new_frame,
408+
PageTableFlags::PRESENT | PageTableFlags::USER_ACCESSIBLE | protection.into(),
409+
&mut FRAME_ALLOCATOR,
410+
)?
411+
.flush();
412+
}
413+
414+
Ok(())
415+
}
416+
371417
/// Handler routine for a COW (Copy-On-Write) pages. A COW page is shared between multiple processes
372418
/// until a write occurs after which a private copy is made for the writing process. A COW page
373419
/// is recognised because the VMA for the region is marked writable even though the individual page
374420
/// table entry is not.
421+
///
422+
/// ## Panics
423+
/// * The provided `address` is not aligned to a page boundary.
375424
fn handle_cow(
376425
&mut self,
377426
offset_table: &mut OffsetPageTable,
378427
address: VirtAddr,
379428
copy: bool,
380429
) -> bool {
430+
debug_assert!(address.is_aligned(Size4KiB::SIZE));
431+
432+
let page: Page<Size4KiB> = Page::containing_address(address);
433+
381434
if let TranslateResult::Mapped { frame, .. } = offset_table.translate(address) {
382-
let addr = frame.start_address();
383-
let page: Page<Size4KiB> = Page::containing_address(address);
435+
let phys_addr = frame.start_address();
384436

385-
if let Some(vm_frame) = addr.as_vm_frame() {
437+
if let Some(vm_frame) = phys_addr.as_vm_frame() {
386438
if vm_frame.ref_count() > 1 || copy {
387439
// This page is used by more then one process, so make it a private copy.
388440
log::trace!(" - making {:?} into a private copy", page);
389-
390-
let frame = pmm_alloc(BuddyOrdering::Size4KiB);
391-
392-
unsafe {
393-
address.as_ptr::<u8>().copy_to(
394-
(crate::PHYSICAL_MEMORY_OFFSET + frame.as_u64()).as_mut_ptr(),
395-
Size4KiB::SIZE as _,
396-
);
397-
}
398-
399-
offset_table.unmap(page).expect("unmap faild").1.flush();
400-
let frame = PhysFrame::containing_address(frame);
401-
402-
unsafe {
403-
offset_table.map_to(
404-
page,
405-
frame,
406-
PageTableFlags::PRESENT
407-
| PageTableFlags::USER_ACCESSIBLE
408-
| self.protection.into(),
409-
&mut FRAME_ALLOCATOR,
410-
)
411-
}
412-
.expect("page mapping failed")
413-
.flush();
441+
Self::map_copied(offset_table, page, self.protection).unwrap();
414442
} else {
415443
// This page is used by only one process, so make it writable.
416444
log::trace!(" - making {:?} writable", page);
@@ -423,7 +451,7 @@ impl Mapping {
423451
| self.protection.into(),
424452
)
425453
}
426-
.expect("failed to update page table flags")
454+
.unwrap()
427455
.flush();
428456
}
429457

0 commit comments

Comments
 (0)