@@ -368,49 +368,77 @@ impl Mapping {
368
368
}
369
369
}
370
370
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
+
371
417
/// Handler routine for a COW (Copy-On-Write) pages. A COW page is shared between multiple processes
372
418
/// until a write occurs after which a private copy is made for the writing process. A COW page
373
419
/// is recognised because the VMA for the region is marked writable even though the individual page
374
420
/// table entry is not.
421
+ ///
422
+ /// ## Panics
423
+ /// * The provided `address` is not aligned to a page boundary.
375
424
fn handle_cow (
376
425
& mut self ,
377
426
offset_table : & mut OffsetPageTable ,
378
427
address : VirtAddr ,
379
428
copy : bool ,
380
429
) -> bool {
430
+ debug_assert ! ( address. is_aligned( Size4KiB :: SIZE ) ) ;
431
+
432
+ let page: Page < Size4KiB > = Page :: containing_address ( address) ;
433
+
381
434
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 ( ) ;
384
436
385
- if let Some ( vm_frame) = addr . as_vm_frame ( ) {
437
+ if let Some ( vm_frame) = phys_addr . as_vm_frame ( ) {
386
438
if vm_frame. ref_count ( ) > 1 || copy {
387
439
// This page is used by more then one process, so make it a private copy.
388
440
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 ( ) ;
414
442
} else {
415
443
// This page is used by only one process, so make it writable.
416
444
log:: trace!( " - making {:?} writable" , page) ;
@@ -423,7 +451,7 @@ impl Mapping {
423
451
| self . protection . into ( ) ,
424
452
)
425
453
}
426
- . expect ( "failed to update page table flags" )
454
+ . unwrap ( )
427
455
. flush ( ) ;
428
456
}
429
457
0 commit comments