|
1 | 1 | use bootloader_api::info::{MemoryRegion, MemoryRegionKind};
|
2 | 2 | use core::{
|
| 3 | + cmp, |
3 | 4 | iter::{empty, Empty},
|
4 | 5 | mem::MaybeUninit,
|
5 | 6 | };
|
@@ -235,93 +236,61 @@ where
|
235 | 236 |
|
236 | 237 | // TODO unit test
|
237 | 238 | fn split_and_add_region<'a, U>(
|
238 |
| - region: MemoryRegion, |
| 239 | + mut region: MemoryRegion, |
239 | 240 | regions: &mut [MaybeUninit<MemoryRegion>],
|
240 | 241 | next_index: &mut usize,
|
241 | 242 | used_slices: U,
|
242 | 243 | ) where
|
243 | 244 | U: Iterator<Item = UsedMemorySlice> + Clone,
|
244 | 245 | {
|
245 | 246 | assert!(region.kind == MemoryRegionKind::Usable);
|
246 |
| - if region.start == region.end { |
247 |
| - // skip zero sized regions |
248 |
| - return; |
249 |
| - } |
250 |
| - |
251 |
| - for slice in used_slices.clone() { |
252 |
| - let slice_end = slice.start + slice.end; |
253 |
| - if region.end <= slice.start || region.start >= slice_end { |
254 |
| - // region and slice don't overlap |
255 |
| - continue; |
256 |
| - } |
257 |
| - |
258 |
| - if region.start >= slice.start && region.end <= slice_end { |
259 |
| - // region is completly covered by slice |
260 |
| - let bootloader = MemoryRegion { |
261 |
| - start: region.start, |
262 |
| - end: region.end, |
263 |
| - kind: MemoryRegionKind::Bootloader, |
264 |
| - }; |
265 |
| - Self::add_region(bootloader, regions, next_index); |
266 |
| - return; |
267 |
| - } |
268 |
| - if region.start < slice.start && region.end <= slice_end { |
269 |
| - // there is a usable region before the bootloader slice |
270 |
| - let before = MemoryRegion { |
271 |
| - start: region.start, |
272 |
| - end: slice.start, |
273 |
| - kind: MemoryRegionKind::Usable, |
274 |
| - }; |
275 |
| - |
276 |
| - let bootloader = MemoryRegion { |
277 |
| - start: slice.start, |
278 |
| - end: region.end, |
279 |
| - kind: MemoryRegionKind::Bootloader, |
280 |
| - }; |
281 |
| - Self::split_and_add_region(before, regions, next_index, used_slices); |
282 |
| - Self::add_region(bootloader, regions, next_index); |
283 |
| - return; |
284 |
| - } else if region.start < slice.start && region.end > slice_end { |
285 |
| - // there is usable region before and after the bootloader slice |
286 |
| - let before = MemoryRegion { |
| 247 | + // Each loop iteration takes a chunk of `region` and adds it to |
| 248 | + // `regions`. Do this until `region` is empty. |
| 249 | + while region.start != region.end { |
| 250 | + // Check if there is overlap between `region` and `used_slices`. |
| 251 | + if let Some((overlap_start, overlap_end)) = used_slices |
| 252 | + .clone() |
| 253 | + .map(|slice| { |
| 254 | + // Calculate the start and end points of the overlap |
| 255 | + // between `slice` and `region`. If `slice` and `region` |
| 256 | + // don't overlap, the range will be ill-formed |
| 257 | + // (overlap_start > overlap_end). |
| 258 | + let overlap_start = cmp::max(region.start, slice.start); |
| 259 | + let overlap_end = cmp::min(region.end, slice.end); |
| 260 | + (overlap_start, overlap_end) |
| 261 | + }) |
| 262 | + .filter(|(overlap_start, overlap_end)| { |
| 263 | + // Only consider non-empty overlap. |
| 264 | + overlap_start < overlap_end |
| 265 | + }) |
| 266 | + .min_by_key(|&(overlap_start, _)| { |
| 267 | + // Find the earliest overlap. |
| 268 | + overlap_start |
| 269 | + }) |
| 270 | + { |
| 271 | + // There's no overlapping used slice before `overlap_start`, so |
| 272 | + // we know that memory between `region.start` and |
| 273 | + // `overlap_start` is usable. |
| 274 | + let usable = MemoryRegion { |
287 | 275 | start: region.start,
|
288 |
| - end: slice.start, |
| 276 | + end: overlap_start, |
289 | 277 | kind: MemoryRegionKind::Usable,
|
290 | 278 | };
|
291 | 279 | let bootloader = MemoryRegion {
|
292 |
| - start: slice.start, |
293 |
| - end: slice_end, |
| 280 | + start: overlap_start, |
| 281 | + end: overlap_end, |
294 | 282 | kind: MemoryRegionKind::Bootloader,
|
295 | 283 | };
|
296 |
| - let after = MemoryRegion { |
297 |
| - start: slice_end, |
298 |
| - end: region.end, |
299 |
| - kind: MemoryRegionKind::Usable, |
300 |
| - }; |
301 |
| - Self::split_and_add_region(before, regions, next_index, used_slices.clone()); |
| 284 | + Self::add_region(usable, regions, next_index); |
302 | 285 | Self::add_region(bootloader, regions, next_index);
|
303 |
| - Self::split_and_add_region(after, regions, next_index, used_slices.clone()); |
304 |
| - return; |
305 |
| - } |
306 |
| - if region.start >= slice.start && region.end > slice_end { |
307 |
| - // there is a usable region after the bootloader slice |
308 |
| - let bootloader = MemoryRegion { |
309 |
| - start: region.start, |
310 |
| - end: slice_end, |
311 |
| - kind: MemoryRegionKind::Bootloader, |
312 |
| - }; |
313 |
| - let after = MemoryRegion { |
314 |
| - start: slice_end, |
315 |
| - end: region.end, |
316 |
| - kind: MemoryRegionKind::Usable, |
317 |
| - }; |
318 |
| - Self::add_region(bootloader, regions, next_index); |
319 |
| - Self::split_and_add_region(after, regions, next_index, used_slices); |
320 |
| - return; |
| 286 | + // Continue after the overlapped region. |
| 287 | + region.start = overlap_end; |
| 288 | + } else { |
| 289 | + // There's no overlap. We can add the whole region. |
| 290 | + Self::add_region(region, regions, next_index); |
| 291 | + break; |
321 | 292 | }
|
322 | 293 | }
|
323 |
| - // region is not coverd by any slice |
324 |
| - Self::add_region(region, regions, next_index); |
325 | 294 | }
|
326 | 295 |
|
327 | 296 | fn add_region(
|
|
0 commit comments