|
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