@@ -4,12 +4,12 @@ use core::fmt;
4
4
5
5
use super :: * ;
6
6
use crate :: registers:: control:: Cr3 ;
7
- use crate :: structures:: paging:: PageTableIndex ;
7
+ use crate :: structures:: paging:: page_table :: PageTableLevel ;
8
8
use crate :: structures:: paging:: {
9
9
frame_alloc:: FrameAllocator ,
10
- page:: { AddressNotAligned , NotGiantPageSize } ,
10
+ page:: { AddressNotAligned , NotGiantPageSize , PageRangeInclusive } ,
11
11
page_table:: { FrameError , PageTable , PageTableEntry , PageTableFlags } ,
12
- Page , PageSize , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
12
+ FrameDeallocator , Page , PageSize , PageTableIndex , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
13
13
} ;
14
14
use crate :: VirtAddr ;
15
15
@@ -829,6 +829,97 @@ impl<'a> Translate for RecursivePageTable<'a> {
829
829
}
830
830
}
831
831
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
+
832
923
/// The given page table was not suitable to create a `RecursivePageTable`.
833
924
#[ derive( Debug ) ]
834
925
pub enum InvalidPageTable {
0 commit comments