@@ -134,19 +134,18 @@ impl UsedLevel4Entries {
134134 }
135135 }
136136
137- /// Returns an unused level 4 entry and marks it as used. If `CONFIG.aslr` is
138- /// enabled, this will return a random available entry .
137+ /// Returns the first index of a `num` contiguous unused level 4 entries and marks them as
138+ /// used. If `CONFIG.aslr` is enabled, this will return random contiguous available entries .
139139 ///
140140 /// Since this method marks each returned index as used, it can be used multiple times
141141 /// to determine multiple unused virtual memory regions.
142- pub fn get_free_entry ( & mut self ) -> PageTableIndex {
143- // Create an iterator over all available p4 indices.
142+ pub fn get_free_entries ( & mut self , num : u64 ) -> PageTableIndex {
143+ // Create an iterator over all available p4 indices with `num` contiguous free entries .
144144 let mut free_entries = self
145145 . entry_state
146- . iter ( )
147- . copied ( )
146+ . windows ( num. into_usize ( ) )
148147 . enumerate ( )
149- . filter ( |( _, used ) | !used)
148+ . filter ( |( _, entries ) | entries . iter ( ) . all ( |used| !used) )
150149 . map ( |( idx, _) | idx) ;
151150
152151 // Choose the free entry index.
@@ -157,30 +156,36 @@ impl UsedLevel4Entries {
157156 // Choose the first index.
158157 free_entries. next ( )
159158 } ;
160- let idx = idx_opt. expect ( "no usable level 4 entry found" ) ;
159+ let idx = idx_opt. expect ( "no usable level 4 entries found" ) ;
161160
162- // Mark the entry as used.
163- self . entry_state [ idx] = true ;
161+ // Mark the entries as used.
162+ for i in 0 ..num. into_usize ( ) {
163+ self . entry_state [ idx + i] = true ;
164+ }
164165
165166 PageTableIndex :: new ( idx. try_into ( ) . unwrap ( ) )
166167 }
167168
168- /// Returns a virtual address in an unused level 4 entry and marks it as used.
169+ /// Returns a virtual address in one or more unused level 4 entries and marks them as used.
169170 ///
170- /// This function calls [`get_free_entry `] internally, so all of its docs applies here
171+ /// This function calls [`get_free_entries `] internally, so all of its docs applies here
171172 /// too.
172173 pub fn get_free_address ( & mut self , size : u64 , alignment : u64 ) -> VirtAddr {
173174 assert ! ( alignment. is_power_of_two( ) ) ;
174175
175- let base =
176- Page :: from_page_table_indices_1gib ( self . get_free_entry ( ) , PageTableIndex :: new ( 0 ) )
177- . start_address ( ) ;
176+ const LEVEL_4_SIZE : u64 = 4096 * 512 * 512 * 512 ;
177+
178+ let level_4_entries = ( size + ( LEVEL_4_SIZE - 1 ) ) / LEVEL_4_SIZE ;
179+ let base = Page :: from_page_table_indices_1gib (
180+ self . get_free_entries ( level_4_entries) ,
181+ PageTableIndex :: new ( 0 ) ,
182+ )
183+ . start_address ( ) ;
178184
179185 let offset = if let Some ( rng) = self . rng . as_mut ( ) {
180186 // Choose a random offset.
181- const LEVEL_4_SIZE : u64 = 4096 * 512 * 512 * 512 ;
182- let end = LEVEL_4_SIZE - size;
183- let uniform_range = Uniform :: from ( 0 ..end / alignment) ;
187+ let max_offset = LEVEL_4_SIZE - ( size % LEVEL_4_SIZE ) ;
188+ let uniform_range = Uniform :: from ( 0 ..max_offset / alignment) ;
184189 uniform_range. sample ( rng) * alignment
185190 } else {
186191 0
0 commit comments