@@ -26,7 +26,8 @@ limitations under the License.
2626//! allocating intermediate tables as needed and setting appropriate flags on leaf PTEs
2727
2828use crate :: vmem:: {
29- BasicMapping , Mapping , MappingKind , TableMovabilityBase , TableOps , TableReadOps , Void ,
29+ BasicMapping , CowMapping , Mapping , MappingKind , TableMovabilityBase , TableOps , TableReadOps ,
30+ Void ,
3031} ;
3132
3233// Paging Flags
@@ -64,6 +65,11 @@ const PAGE_CACHE_ENABLED: u64 = 0 << 4; // PCD - page cache disable bit not set
6465const PAGE_WRITE_BACK : u64 = 0 << 3 ; // PWT - page write-through bit not set (write-back caching)
6566const PAGE_PAT_WB : u64 = 0 << 7 ; // PAT - page attribute table index bit (0 for write-back memory when PCD=0, PWT=0)
6667
68+ // We use various patterns of the available-for-software-use bits to
69+ // represent certain special mappings.
70+ const PTE_AVL_MASK : u64 = 0x0000_0000_0000_0E00 ;
71+ const PAGE_AVL_COW : u64 = 1 << 9 ;
72+
6773/// Returns PAGE_RW if writable is true, 0 otherwise
6874#[ inline( always) ]
6975const fn page_rw_flag ( writable : bool ) -> u64 {
@@ -417,7 +423,7 @@ unsafe fn map_page<
417423 r : MapResponse < Op , P > ,
418424) {
419425 let pte = match & mapping. kind {
420- MappingKind :: BasicMapping ( bm) =>
426+ MappingKind :: Basic ( bm) =>
421427 // TODO: Support not readable
422428 // NOTE: On x86-64, there is no separate "readable" bit in the page table entry.
423429 // This means that pages cannot be made write-only or execute-only without also being readable.
@@ -437,6 +443,19 @@ unsafe fn map_page<
437443 page_rw_flag ( bm. writable ) | // R/W - set if writable
438444 PAGE_PRESENT // P - this entry is present
439445 }
446+ MappingKind :: Cow ( cm) => {
447+ ( mapping. phys_base + ( r. vmin - mapping. virt_base ) ) |
448+ page_nx_flag ( cm. executable ) | // NX - no execute unless allowed
449+ PAGE_AVL_COW |
450+ PAGE_PAT_WB | // PAT index bit for write-back memory
451+ PAGE_DIRTY_CLEAR | // dirty bit (set by CPU when written)
452+ PAGE_ACCESSED_CLEAR | // accessed bit cleared (will be set by CPU when page is accessed - but we dont use the access bit for anything at present)
453+ PAGE_CACHE_ENABLED | // leave caching enabled
454+ PAGE_WRITE_BACK | // use write-back caching
455+ PAGE_USER_ACCESS_DISABLED | // dont allow user access (no code runs in user mode for now)
456+ 0 | // R/W - Cow page is never writable
457+ PAGE_PRESENT // P - this entry is present
458+ }
440459 } ;
441460 unsafe {
442461 write_entry_updating ( op, r. update_parent , r. entry_ptr , pte) ;
@@ -517,7 +536,7 @@ pub unsafe fn virt_to_phys<'a, Op: TableReadOps + 'a>(
517536 op : impl core:: convert:: AsRef < Op > + Copy + ' a ,
518537 address : u64 ,
519538 len : u64 ,
520- ) -> impl Iterator < Item = ( VirtAddr , PhysAddr , BasicMapping ) > + ' a {
539+ ) -> impl Iterator < Item = Mapping > + ' a {
521540 // Undo sign-extension, and mask off any sub-page bits
522541 let vmin = ( address & ( ( 1u64 << VA_BITS ) - 1 ) ) & !( PAGE_SIZE as u64 - 1 ) ;
523542 let vmax = core:: cmp:: min ( vmin + len, 1u64 << VA_BITS ) ;
@@ -540,12 +559,27 @@ pub unsafe fn virt_to_phys<'a, Op: TableReadOps + 'a>(
540559 let sgn_bit = r. vmin >> ( VA_BITS - 1 ) ;
541560 let sgn_bits = 0u64 . wrapping_sub ( sgn_bit) << VA_BITS ;
542561 let virt_addr = sgn_bits | r. vmin ;
543- let perms = BasicMapping {
544- readable : true ,
545- writable : ( pte & PAGE_RW ) != 0 ,
546- executable : ( pte & PAGE_NX ) == 0 ,
562+
563+ let executable = ( pte & PAGE_NX ) == 0 ;
564+ let avl = pte & PTE_AVL_MASK ;
565+ let kind = if avl == PAGE_AVL_COW {
566+ MappingKind :: Cow ( CowMapping {
567+ readable : true ,
568+ executable,
569+ } )
570+ } else {
571+ MappingKind :: Basic ( BasicMapping {
572+ readable : true ,
573+ writable : ( pte & PAGE_RW ) != 0 ,
574+ executable,
575+ } )
547576 } ;
548- Some ( ( virt_addr, phys_addr, perms) )
577+ Some ( Mapping {
578+ phys_base : phys_addr,
579+ virt_base : virt_addr,
580+ len : PAGE_SIZE as u64 ,
581+ kind,
582+ } )
549583 } )
550584}
551585
@@ -721,7 +755,7 @@ mod tests {
721755 phys_base : 0x1000 ,
722756 virt_base : 0x1000 ,
723757 len : PAGE_SIZE as u64 ,
724- kind : MappingKind :: BasicMapping ( BasicMapping {
758+ kind : MappingKind :: Basic ( BasicMapping {
725759 readable : true ,
726760 writable : true ,
727761 executable : false ,
@@ -754,7 +788,7 @@ mod tests {
754788 phys_base : 0x2000 ,
755789 virt_base : 0x2000 ,
756790 len : PAGE_SIZE as u64 ,
757- kind : MappingKind :: BasicMapping ( BasicMapping {
791+ kind : MappingKind :: Basic ( BasicMapping {
758792 readable : true ,
759793 writable : false ,
760794 executable : true ,
@@ -777,7 +811,7 @@ mod tests {
777811 phys_base : 0x10000 ,
778812 virt_base : 0x10000 ,
779813 len : 4 * PAGE_SIZE as u64 , // 4 pages = 16KB
780- kind : MappingKind :: BasicMapping ( BasicMapping {
814+ kind : MappingKind :: Basic ( BasicMapping {
781815 readable : true ,
782816 writable : true ,
783817 executable : false ,
@@ -810,7 +844,7 @@ mod tests {
810844 phys_base : 0x1000 ,
811845 virt_base : 0x1000 ,
812846 len : PAGE_SIZE as u64 ,
813- kind : MappingKind :: BasicMapping ( BasicMapping {
847+ kind : MappingKind :: Basic ( BasicMapping {
814848 readable : true ,
815849 writable : true ,
816850 executable : false ,
@@ -824,7 +858,7 @@ mod tests {
824858 phys_base : 0x5000 ,
825859 virt_base : 0x5000 ,
826860 len : PAGE_SIZE as u64 ,
827- kind : MappingKind :: BasicMapping ( BasicMapping {
861+ kind : MappingKind :: Basic ( BasicMapping {
828862 readable : true ,
829863 writable : true ,
830864 executable : false ,
@@ -849,7 +883,7 @@ mod tests {
849883 phys_base : 0x1000 ,
850884 virt_base : 0x1000 ,
851885 len : PAGE_SIZE as u64 ,
852- kind : MappingKind :: BasicMapping ( BasicMapping {
886+ kind : MappingKind :: Basic ( BasicMapping {
853887 readable : true ,
854888 writable : true ,
855889 executable : false ,
@@ -860,8 +894,75 @@ mod tests {
860894
861895 let result = unsafe { virt_to_phys ( & ops, 0x1000 , 1 ) . next ( ) } ;
862896 assert ! ( result. is_some( ) , "Should find mapped address" ) ;
863- let pte = result. unwrap ( ) ;
864- assert_eq ! ( pte. 1 , 0x1000 ) ;
897+ let mapping = result. unwrap ( ) ;
898+ assert_eq ! ( mapping. phys_base, 0x1000 ) ;
899+ }
900+
901+ #[ test]
902+ fn test_virt_to_phys_unaligned_virt ( ) {
903+ let ops = MockTableOps :: new ( ) ;
904+ let mapping = Mapping {
905+ phys_base : 0x1000 ,
906+ virt_base : 0x1000 ,
907+ len : PAGE_SIZE as u64 ,
908+ kind : MappingKind :: Basic ( BasicMapping {
909+ readable : true ,
910+ writable : true ,
911+ executable : false ,
912+ } ) ,
913+ } ;
914+
915+ unsafe { map ( & ops, mapping) } ;
916+
917+ let result = unsafe { virt_to_phys ( & ops, 0x1234 , 1 ) . next ( ) } ;
918+ assert ! ( result. is_some( ) , "Should find mapped address" ) ;
919+ let mapping = result. unwrap ( ) ;
920+ assert_eq ! ( mapping. phys_base, 0x1000 ) ;
921+ }
922+
923+ #[ test]
924+ fn test_virt_to_phys_perms ( ) {
925+ let test = |kind| {
926+ let ops = MockTableOps :: new ( ) ;
927+ let mapping = Mapping {
928+ phys_base : 0x1000 ,
929+ virt_base : 0x1000 ,
930+ len : PAGE_SIZE as u64 ,
931+ kind,
932+ } ;
933+ unsafe { map ( & ops, mapping) } ;
934+ let result = unsafe { virt_to_phys ( & ops, 0x1000 , 1 ) . next ( ) } ;
935+ let mapping = result. unwrap ( ) ;
936+ assert_eq ! ( mapping. kind, kind) ;
937+ } ;
938+ test ( MappingKind :: Basic ( BasicMapping {
939+ readable : true ,
940+ writable : false ,
941+ executable : false ,
942+ } ) ) ;
943+ test ( MappingKind :: Basic ( BasicMapping {
944+ readable : true ,
945+ writable : false ,
946+ executable : true ,
947+ } ) ) ;
948+ test ( MappingKind :: Basic ( BasicMapping {
949+ readable : true ,
950+ writable : true ,
951+ executable : false ,
952+ } ) ) ;
953+ test ( MappingKind :: Basic ( BasicMapping {
954+ readable : true ,
955+ writable : true ,
956+ executable : true ,
957+ } ) ) ;
958+ test ( MappingKind :: Cow ( CowMapping {
959+ readable : true ,
960+ executable : false ,
961+ } ) ) ;
962+ test ( MappingKind :: Cow ( CowMapping {
963+ readable : true ,
964+ executable : true ,
965+ } ) ) ;
865966 }
866967
867968 #[ test]
@@ -880,7 +981,7 @@ mod tests {
880981 phys_base : 0x1000 ,
881982 virt_base : 0x1000 ,
882983 len : PAGE_SIZE as u64 ,
883- kind : MappingKind :: BasicMapping ( BasicMapping {
984+ kind : MappingKind :: Basic ( BasicMapping {
884985 readable : true ,
885986 writable : true ,
886987 executable : false ,
0 commit comments