@@ -131,19 +131,18 @@ impl UsedLevel4Entries {
131131 }
132132 }
133133
134- /// Returns an unused level 4 entry and marks it as used. If `CONFIG.aslr` is
135- /// enabled, this will return a random available entry .
134+ /// Returns the first index of a `num` contiguous unused level 4 entries and marks them as
135+ /// used. If `CONFIG.aslr` is enabled, this will return random contiguous available entries .
136136 ///
137137 /// Since this method marks each returned index as used, it can be used multiple times
138138 /// to determine multiple unused virtual memory regions.
139- pub fn get_free_entry ( & mut self ) -> PageTableIndex {
140- // Create an iterator over all available p4 indices.
139+ pub fn get_free_entries ( & mut self , num : u64 ) -> PageTableIndex {
140+ // Create an iterator over all available p4 indices with `num` contiguous free entries .
141141 let mut free_entries = self
142142 . entry_state
143- . iter ( )
144- . copied ( )
143+ . windows ( num. into_usize ( ) )
145144 . enumerate ( )
146- . filter ( |( _, used ) | !used)
145+ . filter ( |( _, entries ) | entries . iter ( ) . all ( |used| !used) )
147146 . map ( |( idx, _) | idx) ;
148147
149148 // Choose the free entry index.
@@ -154,30 +153,36 @@ impl UsedLevel4Entries {
154153 // Choose the first index.
155154 free_entries. next ( )
156155 } ;
157- let idx = idx_opt. expect ( "no usable level 4 entry found" ) ;
156+ let idx = idx_opt. expect ( "no usable level 4 entries found" ) ;
158157
159- // Mark the entry as used.
160- self . entry_state [ idx] = true ;
158+ // Mark the entries as used.
159+ for i in 0 ..num. into_usize ( ) {
160+ self . entry_state [ idx + i] = true ;
161+ }
161162
162163 PageTableIndex :: new ( idx. try_into ( ) . unwrap ( ) )
163164 }
164165
165- /// Returns a virtual address in an unused level 4 entry and marks it as used.
166+ /// Returns a virtual address in one or more unused level 4 entries and marks them as used.
166167 ///
167- /// This function calls [`get_free_entry `] internally, so all of its docs applies here
168+ /// This function calls [`get_free_entries `] internally, so all of its docs applies here
168169 /// too.
169170 pub fn get_free_address ( & mut self , size : u64 , alignment : u64 ) -> VirtAddr {
170171 assert ! ( alignment. is_power_of_two( ) ) ;
171172
172- let base =
173- Page :: from_page_table_indices_1gib ( self . get_free_entry ( ) , PageTableIndex :: new ( 0 ) )
174- . start_address ( ) ;
173+ const LEVEL_4_SIZE : u64 = 4096 * 512 * 512 * 512 ;
174+
175+ let level_4_entries = ( size + ( LEVEL_4_SIZE - 1 ) ) / LEVEL_4_SIZE ;
176+ let base = Page :: from_page_table_indices_1gib (
177+ self . get_free_entries ( level_4_entries) ,
178+ PageTableIndex :: new ( 0 ) ,
179+ )
180+ . start_address ( ) ;
175181
176182 let offset = if let Some ( rng) = self . rng . as_mut ( ) {
177183 // Choose a random offset.
178- const LEVEL_4_SIZE : u64 = 4096 * 512 * 512 * 512 ;
179- let end = LEVEL_4_SIZE - size;
180- let uniform_range = Uniform :: from ( 0 ..end / alignment) ;
184+ let max_offset = LEVEL_4_SIZE - ( size % LEVEL_4_SIZE ) ;
185+ let uniform_range = Uniform :: from ( 0 ..max_offset / alignment) ;
181186 uniform_range. sample ( rng) * alignment
182187 } else {
183188 0
0 commit comments