@@ -27,6 +27,8 @@ const fn p1_index(vaddr: usize) -> usize {
2727/// When the [`PageTable64`] itself is dropped.
2828pub struct PageTable64 < M : PagingMetaData , PTE : GenericPTE , H : PagingHandler > {
2929 root_paddr : PhysAddr ,
30+ #[ cfg( feature = "copy-from" ) ]
31+ borrowed_entries : bitmaps:: Bitmap < ENTRY_COUNT > ,
3032 _phantom : PhantomData < ( M , PTE , H ) > ,
3133}
3234
@@ -38,6 +40,8 @@ impl<M: PagingMetaData, PTE: GenericPTE, H: PagingHandler> PageTable64<M, PTE, H
3840 let root_paddr = Self :: alloc_table ( ) ?;
3941 Ok ( Self {
4042 root_paddr,
43+ #[ cfg( feature = "copy-from" ) ]
44+ borrowed_entries : bitmaps:: Bitmap :: new ( ) ,
4145 _phantom : PhantomData ,
4246 } )
4347 }
@@ -325,6 +329,7 @@ impl<M: PagingMetaData, PTE: GenericPTE, H: PagingHandler> PageTable64<M, PTE, H
325329 }
326330
327331 /// Copy entries from another page table within the given virtual memory range.
332+ #[ cfg( feature = "copy-from" ) ]
328333 pub fn copy_from ( & mut self , other : & Self , start : M :: VirtAddr , size : usize ) {
329334 if size == 0 {
330335 return ;
@@ -342,7 +347,13 @@ impl<M: PagingMetaData, PTE: GenericPTE, H: PagingHandler> PageTable64<M, PTE, H
342347 let end_idx = index_fn ( start. into ( ) + size - 1 ) + 1 ;
343348 assert ! ( start_idx < ENTRY_COUNT ) ;
344349 assert ! ( end_idx <= ENTRY_COUNT ) ;
345- dst_table[ start_idx..end_idx] . copy_from_slice ( & src_table[ start_idx..end_idx] ) ;
350+ for i in start_idx..end_idx {
351+ let entry = & mut dst_table[ i] ;
352+ if !self . borrowed_entries . set ( i, true ) {
353+ self . dealloc_tree ( entry, 1 ) ;
354+ }
355+ * entry = src_table[ i] ;
356+ }
346357 }
347358}
348359
@@ -520,20 +531,31 @@ impl<M: PagingMetaData, PTE: GenericPTE, H: PagingHandler> PageTable64<M, PTE, H
520531 }
521532 Ok ( ( ) )
522533 }
534+
535+ fn dealloc_tree ( & self , entry : & PTE , level : usize ) {
536+ // don't free the entries in last level, they are not array.
537+ if level < M :: LEVELS - 1 {
538+ if let Ok ( table) = self . next_table ( entry) {
539+ for entry in table {
540+ self . dealloc_tree ( entry, level + 1 ) ;
541+ }
542+ H :: dealloc_frame ( entry. paddr ( ) ) ;
543+ }
544+ }
545+ }
523546}
524547
525548impl < M : PagingMetaData , PTE : GenericPTE , H : PagingHandler > Drop for PageTable64 < M , PTE , H > {
526549 fn drop ( & mut self ) {
527- // don't free the entries in last level, they are not array.
528- let _ = self . walk (
529- usize:: MAX ,
530- None ,
531- Some ( & |level, _index, _vaddr, entry : & PTE | {
532- if level < M :: LEVELS - 1 && entry. is_present ( ) && !entry. is_huge ( ) {
533- H :: dealloc_frame ( entry. paddr ( ) ) ;
534- }
535- } ) ,
536- ) ;
550+ let root = self . table_of ( self . root_paddr ) ;
551+ #[ allow( unused_variables) ]
552+ for ( i, entry) in root. iter ( ) . enumerate ( ) {
553+ #[ cfg( feature = "copy-from" ) ]
554+ if self . borrowed_entries . get ( i) {
555+ continue ;
556+ }
557+ self . dealloc_tree ( entry, 1 ) ;
558+ }
537559 H :: dealloc_frame ( self . root_paddr ( ) ) ;
538560 }
539561}
0 commit comments