@@ -4,12 +4,12 @@ use core::fmt;
44
55use super :: * ;
66use crate :: registers:: control:: Cr3 ;
7- use crate :: structures:: paging:: PageTableIndex ;
7+ use crate :: structures:: paging:: page_table :: PageTableLevel ;
88use crate :: structures:: paging:: {
99 frame_alloc:: FrameAllocator ,
10- page:: { AddressNotAligned , NotGiantPageSize } ,
10+ page:: { AddressNotAligned , NotGiantPageSize , PageRangeInclusive } ,
1111 page_table:: { FrameError , PageTable , PageTableEntry , PageTableFlags } ,
12- Page , PageSize , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
12+ FrameDeallocator , Page , PageSize , PageTableIndex , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
1313} ;
1414use crate :: VirtAddr ;
1515
@@ -829,6 +829,97 @@ impl<'a> Translate for RecursivePageTable<'a> {
829829 }
830830}
831831
832+ impl < ' a > CleanUp for RecursivePageTable < ' a > {
833+ #[ inline]
834+ unsafe fn clean_up < D > ( & mut self , frame_deallocator : & mut D )
835+ where
836+ D : FrameDeallocator < Size4KiB > ,
837+ {
838+ self . clean_up_addr_range (
839+ PageRangeInclusive {
840+ start : Page :: from_start_address ( VirtAddr :: new ( 0 ) ) . unwrap ( ) ,
841+ end : Page :: from_start_address ( VirtAddr :: new ( 0xffff_ffff_ffff_f000 ) ) . unwrap ( ) ,
842+ } ,
843+ frame_deallocator,
844+ )
845+ }
846+
847+ unsafe fn clean_up_addr_range < D > (
848+ & mut self ,
849+ range : PageRangeInclusive ,
850+ frame_deallocator : & mut D ,
851+ ) where
852+ D : FrameDeallocator < Size4KiB > ,
853+ {
854+ fn clean_up (
855+ recursive_index : PageTableIndex ,
856+ page_table : & mut PageTable ,
857+ level : PageTableLevel ,
858+ range : PageRangeInclusive ,
859+ frame_deallocator : & mut impl FrameDeallocator < Size4KiB > ,
860+ ) -> bool {
861+ if range. is_empty ( ) {
862+ return false ;
863+ }
864+
865+ let table_addr = range
866+ . start
867+ . start_address ( )
868+ . align_down ( level. table_address_space_alignment ( ) ) ;
869+
870+ let start = range. start . page_table_index ( level) ;
871+ let end = range. end . page_table_index ( level) ;
872+
873+ if let Some ( next_level) = level. next_lower_level ( ) {
874+ let offset_per_entry = level. entry_address_space_alignment ( ) ;
875+ for ( i, entry) in page_table
876+ . iter_mut ( )
877+ . enumerate ( )
878+ . take ( usize:: from ( end) + 1 )
879+ . skip ( usize:: from ( start) )
880+ . filter ( |( i, _) | {
881+ !( level == PageTableLevel :: Four && * i == recursive_index. into ( ) )
882+ } )
883+ {
884+ if let Ok ( frame) = entry. frame ( ) {
885+ let start = table_addr + ( offset_per_entry * ( i as u64 ) ) ;
886+ let end = start + ( offset_per_entry - 1 ) ;
887+ let start = Page :: < Size4KiB > :: containing_address ( start) ;
888+ let start = start. max ( range. start ) ;
889+ let end = Page :: < Size4KiB > :: containing_address ( end) ;
890+ let end = end. min ( range. end ) ;
891+ let page_table =
892+ [ p1_ptr, p2_ptr, p3_ptr] [ level as usize - 2 ] ( start, recursive_index) ;
893+ let page_table = unsafe { & mut * page_table } ;
894+ if clean_up (
895+ recursive_index,
896+ page_table,
897+ next_level,
898+ Page :: range_inclusive ( start, end) ,
899+ frame_deallocator,
900+ ) {
901+ entry. set_unused ( ) ;
902+ unsafe {
903+ frame_deallocator. deallocate_frame ( frame) ;
904+ }
905+ }
906+ }
907+ }
908+ }
909+
910+ page_table. iter ( ) . all ( PageTableEntry :: is_unused)
911+ }
912+
913+ clean_up (
914+ self . recursive_index ,
915+ self . level_4_table ( ) ,
916+ PageTableLevel :: Four ,
917+ range,
918+ frame_deallocator,
919+ ) ;
920+ }
921+ }
922+
832923/// The given page table was not suitable to create a `RecursivePageTable`.
833924#[ derive( Debug ) ]
834925pub enum InvalidPageTable {
0 commit comments