@@ -131,19 +131,18 @@ impl UsedLevel4Entries {
131
131
}
132
132
}
133
133
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 .
136
136
///
137
137
/// Since this method marks each returned index as used, it can be used multiple times
138
138
/// 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 .
141
141
let mut free_entries = self
142
142
. entry_state
143
- . iter ( )
144
- . copied ( )
143
+ . windows ( num. into_usize ( ) )
145
144
. enumerate ( )
146
- . filter ( |( _, used ) | !used)
145
+ . filter ( |( _, entries ) | entries . iter ( ) . all ( |used| !used) )
147
146
. map ( |( idx, _) | idx) ;
148
147
149
148
// Choose the free entry index.
@@ -154,30 +153,36 @@ impl UsedLevel4Entries {
154
153
// Choose the first index.
155
154
free_entries. next ( )
156
155
} ;
157
- let idx = idx_opt. expect ( "no usable level 4 entry found" ) ;
156
+ let idx = idx_opt. expect ( "no usable level 4 entries found" ) ;
158
157
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
+ }
161
162
162
163
PageTableIndex :: new ( idx. try_into ( ) . unwrap ( ) )
163
164
}
164
165
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.
166
167
///
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
168
169
/// too.
169
170
pub fn get_free_address ( & mut self , size : u64 , alignment : u64 ) -> VirtAddr {
170
171
assert ! ( alignment. is_power_of_two( ) ) ;
171
172
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 ( ) ;
175
181
176
182
let offset = if let Some ( rng) = self . rng . as_mut ( ) {
177
183
// 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) ;
181
186
uniform_range. sample ( rng) * alignment
182
187
} else {
183
188
0
0 commit comments