@@ -13,7 +13,7 @@ use x86_64::{
1313#[ derive( Clone , Copy , Debug ) ]
1414pub struct UsedMemorySlice {
1515 /// the physical start of the slice
16- pub start : PhysAddr ,
16+ pub start : u64 ,
1717 /// the length of the slice
1818 pub len : u64 ,
1919}
@@ -78,7 +78,7 @@ impl<I, D, S> LegacyFrameAllocator<I, D, S>
7878where
7979 I : ExactSizeIterator < Item = D > + Clone ,
8080 I :: Item : LegacyMemoryRegion ,
81- S : Iterator < Item = UsedMemorySlice > ,
81+ S : Iterator < Item = UsedMemorySlice > + Clone ,
8282{
8383 pub fn new_with_used_slices ( start_frame : PhysFrame , memory_map : I , used_slices : S ) -> Self {
8484 // skip frame 0 because the rust core library does not see 0 as a valid address
@@ -154,64 +154,19 @@ where
154154 ramdisk_slice_start : Option < PhysAddr > ,
155155 ramdisk_slice_len : u64 ,
156156 ) -> & mut [ MemoryRegion ] {
157- let mut next_index = 0 ;
158- let kernel_slice_start = kernel_slice_start. as_u64 ( ) ;
159- let ramdisk_slice_start = ramdisk_slice_start. map ( |a| a. as_u64 ( ) ) ;
157+ let used_slices = Self :: used_regions_iter (
158+ self . min_frame ,
159+ self . next_frame ,
160+ kernel_slice_start,
161+ kernel_slice_len,
162+ ramdisk_slice_start,
163+ ramdisk_slice_len,
164+ self . used_slices ,
165+ ) ;
160166
167+ let mut next_index = 0 ;
161168 for descriptor in self . original {
162- let mut start = descriptor. start ( ) ;
163- let end = start + descriptor. len ( ) ;
164- let next_free = self . next_frame . start_address ( ) ;
165169 let kind = match descriptor. kind ( ) {
166- MemoryRegionKind :: Usable => {
167- if end <= next_free && start >= self . min_frame . start_address ( ) {
168- MemoryRegionKind :: Bootloader
169- } else if descriptor. start ( ) >= next_free {
170- MemoryRegionKind :: Usable
171- } else if end <= self . min_frame . start_address ( ) {
172- // treat regions before min_frame as usable
173- // this allows for access to the lower 1MB of frames
174- MemoryRegionKind :: Usable
175- } else if end <= next_free {
176- // part of the region is used -> add it separately
177- // first part of the region is in lower 1MB, later part is used
178- let free_region = MemoryRegion {
179- start : descriptor. start ( ) . as_u64 ( ) ,
180- end : self . min_frame . start_address ( ) . as_u64 ( ) ,
181- kind : MemoryRegionKind :: Usable ,
182- } ;
183- Self :: add_region ( free_region, regions, & mut next_index) ;
184-
185- // add bootloader part normally
186- start = self . min_frame . start_address ( ) ;
187- MemoryRegionKind :: Bootloader
188- } else {
189- if start < self . min_frame . start_address ( ) {
190- // part of the region is in lower memory
191- let lower_region = MemoryRegion {
192- start : start. as_u64 ( ) ,
193- end : self . min_frame . start_address ( ) . as_u64 ( ) ,
194- kind : MemoryRegionKind :: Usable ,
195- } ;
196- Self :: add_region ( lower_region, regions, & mut next_index) ;
197-
198- start = self . min_frame . start_address ( ) ;
199- }
200-
201- // part of the region is used -> add it separately
202- // first part of the region is used, later part is free
203- let used_region = MemoryRegion {
204- start : start. as_u64 ( ) ,
205- end : next_free. as_u64 ( ) ,
206- kind : MemoryRegionKind :: Bootloader ,
207- } ;
208- Self :: add_region ( used_region, regions, & mut next_index) ;
209-
210- // add unused part normally
211- start = next_free;
212- MemoryRegionKind :: Usable
213- }
214- }
215170 _ if descriptor. usable_after_bootloader_exit ( ) => {
216171 // Region was not usable before, but it will be as soon as
217172 // the bootloader passes control to the kernel. We don't
@@ -223,97 +178,15 @@ where
223178 other => other,
224179 } ;
225180
181+ let end = descriptor. start ( ) + descriptor. len ( ) ;
226182 let region = MemoryRegion {
227- start : start. as_u64 ( ) ,
183+ start : descriptor . start ( ) . as_u64 ( ) ,
228184 end : end. as_u64 ( ) ,
229185 kind,
230186 } ;
231-
232- // check if region overlaps with kernel or ramdisk
233- let kernel_slice_end = kernel_slice_start + kernel_slice_len;
234- let ramdisk_slice_end = ramdisk_slice_start. map ( |s| s + ramdisk_slice_len) ;
235- if region. kind == MemoryRegionKind :: Usable
236- && kernel_slice_start < region. end
237- && kernel_slice_end > region. start
238- {
239- // region overlaps with kernel -> we might need to split it
240-
241- // ensure that the kernel allocation does not span multiple regions
242- assert ! (
243- kernel_slice_start >= region. start,
244- "region overlaps with kernel, but kernel begins before region \
245- (kernel_slice_start: {kernel_slice_start:#x}, region_start: {:#x})",
246- region. start
247- ) ;
248- assert ! (
249- kernel_slice_end <= region. end,
250- "region overlaps with kernel, but region ends before kernel \
251- (kernel_slice_end: {kernel_slice_end:#x}, region_end: {:#x})",
252- region. end,
253- ) ;
254-
255- // split the region into three parts
256- let before_kernel = MemoryRegion {
257- end : kernel_slice_start,
258- ..region
259- } ;
260- let kernel = MemoryRegion {
261- start : kernel_slice_start,
262- end : kernel_slice_end,
263- kind : MemoryRegionKind :: Bootloader ,
264- } ;
265- let after_kernel = MemoryRegion {
266- start : kernel_slice_end,
267- ..region
268- } ;
269-
270- // add the three regions (empty regions are ignored in `add_region`)
271- Self :: add_region ( before_kernel, regions, & mut next_index) ;
272- Self :: add_region ( kernel, regions, & mut next_index) ;
273- Self :: add_region ( after_kernel, regions, & mut next_index) ;
274- } else if region. kind == MemoryRegionKind :: Usable
275- && ramdisk_slice_start. map ( |s| s < region. end ) . unwrap_or ( false )
276- && ramdisk_slice_end. map ( |e| e > region. start ) . unwrap_or ( false )
277- {
278- // region overlaps with ramdisk -> we might need to split it
279- let ramdisk_slice_start = ramdisk_slice_start. unwrap ( ) ;
280- let ramdisk_slice_end = ramdisk_slice_end. unwrap ( ) ;
281-
282- // ensure that the ramdisk allocation does not span multiple regions
283- assert ! (
284- ramdisk_slice_start >= region. start,
285- "region overlaps with ramdisk, but ramdisk begins before region \
286- (ramdisk_start: {ramdisk_slice_start:#x}, region_start: {:#x})",
287- region. start
288- ) ;
289- assert ! (
290- ramdisk_slice_end <= region. end,
291- "region overlaps with ramdisk, but region ends before ramdisk \
292- (ramdisk_end: {ramdisk_slice_end:#x}, region_end: {:#x})",
293- region. end,
294- ) ;
295-
296- // split the region into three parts
297- let before_ramdisk = MemoryRegion {
298- end : ramdisk_slice_start,
299- ..region
300- } ;
301- let ramdisk = MemoryRegion {
302- start : ramdisk_slice_start,
303- end : ramdisk_slice_end,
304- kind : MemoryRegionKind :: Bootloader ,
305- } ;
306- let after_ramdisk = MemoryRegion {
307- start : ramdisk_slice_end,
308- ..region
309- } ;
310-
311- // add the three regions (empty regions are ignored in `add_region`)
312- Self :: add_region ( before_ramdisk, regions, & mut next_index) ;
313- Self :: add_region ( ramdisk, regions, & mut next_index) ;
314- Self :: add_region ( after_ramdisk, regions, & mut next_index) ;
187+ if region. kind == MemoryRegionKind :: Usable {
188+ Self :: split_and_add_region ( region, regions, & mut next_index, used_slices. clone ( ) ) ;
315189 } else {
316- // add the region normally
317190 Self :: add_region ( region, regions, & mut next_index) ;
318191 }
319192 }
@@ -326,6 +199,125 @@ where
326199 }
327200 }
328201
202+ fn used_regions_iter (
203+ min_frame : PhysFrame ,
204+ next_free : PhysFrame ,
205+ kernel_slice_start : PhysAddr ,
206+ kernel_slice_len : u64 ,
207+ ramdisk_slice_start : Option < PhysAddr > ,
208+ ramdisk_slice_len : u64 ,
209+ used_slices : S ,
210+ ) -> impl Iterator < Item = UsedMemorySlice > + Clone {
211+ BootloaderUsedMemorySliceIter {
212+ bootloader : UsedMemorySlice {
213+ start : min_frame. start_address ( ) . as_u64 ( ) ,
214+ // TODO: unit test that this is not an off by 1
215+ len : next_free. start_address ( ) - min_frame. start_address ( ) ,
216+ } ,
217+ kernel : UsedMemorySlice {
218+ start : kernel_slice_start. as_u64 ( ) ,
219+ len : kernel_slice_len,
220+ } ,
221+ ramdisk : ramdisk_slice_start. map ( |start| UsedMemorySlice {
222+ start : start. as_u64 ( ) ,
223+ len : ramdisk_slice_len,
224+ } ) ,
225+ state : KernelRamIterState :: Bootloader ,
226+ }
227+ . chain ( used_slices)
228+ }
229+
230+ // TODO unit test
231+ fn split_and_add_region < ' a , U > (
232+ region : MemoryRegion ,
233+ regions : & mut [ MaybeUninit < MemoryRegion > ] ,
234+ next_index : & mut usize ,
235+ used_slices : U ,
236+ ) where
237+ U : Iterator < Item = UsedMemorySlice > + Clone ,
238+ {
239+ assert ! ( region. kind == MemoryRegionKind :: Usable ) ;
240+ if region. start == region. end {
241+ // skip zero sized regions
242+ return ;
243+ }
244+
245+ for slice in used_slices. clone ( ) {
246+ let slice_end = slice. start + slice. len ;
247+ if region. end <= slice. start || region. start >= slice_end {
248+ // region and slice don't overlap
249+ continue ;
250+ }
251+
252+ if region. start >= slice. start && region. end <= slice_end {
253+ // region is completly covered by slice
254+ let bootloader = MemoryRegion {
255+ start : region. start ,
256+ end : region. end ,
257+ kind : MemoryRegionKind :: Bootloader ,
258+ } ;
259+ Self :: add_region ( bootloader, regions, next_index) ;
260+ return ;
261+ }
262+ if region. start < slice. start && region. end <= slice_end {
263+ // there is a usable region before the bootloader slice
264+ let before = MemoryRegion {
265+ start : region. start ,
266+ end : slice. start ,
267+ kind : MemoryRegionKind :: Usable ,
268+ } ;
269+
270+ let bootloader = MemoryRegion {
271+ start : slice. start ,
272+ end : region. end ,
273+ kind : MemoryRegionKind :: Bootloader ,
274+ } ;
275+ Self :: split_and_add_region ( before, regions, next_index, used_slices) ;
276+ Self :: add_region ( bootloader, regions, next_index) ;
277+ return ;
278+ } else if region. start < slice. start && region. end > slice_end {
279+ // there is usable region before and after the bootloader slice
280+ let before = MemoryRegion {
281+ start : region. start ,
282+ end : slice. start ,
283+ kind : MemoryRegionKind :: Usable ,
284+ } ;
285+ let bootloader = MemoryRegion {
286+ start : slice. start ,
287+ end : slice_end,
288+ kind : MemoryRegionKind :: Bootloader ,
289+ } ;
290+ let after = MemoryRegion {
291+ start : slice_end,
292+ end : region. end ,
293+ kind : MemoryRegionKind :: Usable ,
294+ } ;
295+ Self :: split_and_add_region ( before, regions, next_index, used_slices. clone ( ) ) ;
296+ Self :: add_region ( bootloader, regions, next_index) ;
297+ Self :: split_and_add_region ( after, regions, next_index, used_slices. clone ( ) ) ;
298+ return ;
299+ }
300+ if region. start >= slice. start && region. end > slice_end {
301+ // there is a usable region after the bootloader slice
302+ let bootloader = MemoryRegion {
303+ start : region. start ,
304+ end : slice_end,
305+ kind : MemoryRegionKind :: Bootloader ,
306+ } ;
307+ let after = MemoryRegion {
308+ start : slice_end,
309+ end : region. end ,
310+ kind : MemoryRegionKind :: Usable ,
311+ } ;
312+ Self :: add_region ( bootloader, regions, next_index) ;
313+ Self :: split_and_add_region ( after, regions, next_index, used_slices) ;
314+ return ;
315+ }
316+ }
317+ // region is not coverd by any slice
318+ Self :: add_region ( region, regions, next_index) ;
319+ }
320+
329321 fn add_region (
330322 region : MemoryRegion ,
331323 regions : & mut [ MaybeUninit < MemoryRegion > ] ,
@@ -350,7 +342,7 @@ unsafe impl<I, D, S> FrameAllocator<Size4KiB> for LegacyFrameAllocator<I, D, S>
350342where
351343 I : ExactSizeIterator < Item = D > + Clone ,
352344 I :: Item : LegacyMemoryRegion ,
353- S : Iterator < Item = UsedMemorySlice > ,
345+ S : Iterator < Item = UsedMemorySlice > + Clone ,
354346{
355347 fn allocate_frame ( & mut self ) -> Option < PhysFrame < Size4KiB > > {
356348 if let Some ( current_descriptor) = self . current_descriptor {
@@ -376,3 +368,41 @@ where
376368 None
377369 }
378370}
371+
372+ #[ derive( Clone ) ]
373+ struct BootloaderUsedMemorySliceIter {
374+ bootloader : UsedMemorySlice ,
375+ kernel : UsedMemorySlice ,
376+ ramdisk : Option < UsedMemorySlice > ,
377+ state : KernelRamIterState ,
378+ }
379+
380+ #[ derive( Clone ) ]
381+ enum KernelRamIterState {
382+ Bootloader ,
383+ Kernel ,
384+ Ramdisk ,
385+ Done ,
386+ }
387+
388+ impl Iterator for BootloaderUsedMemorySliceIter {
389+ type Item = UsedMemorySlice ;
390+
391+ fn next ( & mut self ) -> Option < Self :: Item > {
392+ match self . state {
393+ KernelRamIterState :: Bootloader => {
394+ self . state = KernelRamIterState :: Kernel ;
395+ Some ( self . bootloader )
396+ }
397+ KernelRamIterState :: Kernel => {
398+ self . state = KernelRamIterState :: Ramdisk ;
399+ Some ( self . kernel )
400+ }
401+ KernelRamIterState :: Ramdisk => {
402+ self . state = KernelRamIterState :: Done ;
403+ self . ramdisk
404+ }
405+ KernelRamIterState :: Done => None ,
406+ }
407+ }
408+ }
0 commit comments