@@ -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