Skip to content

Commit 941fc73

Browse files
Unify allocation method
Prior to this patch, fixed and regular allocations used two different allocation methods, FixedUntypedAlloc and ObjectAllocator respectively. These operated on the same underlying untyped objects but did not maintain coherency about how much of the untyped had already been allocated, which lead to runtime invocation errors when an untyped contains both fixed and regular allocations. This patch removes FixedUntypedAlloc and changes everything to use ObjectAlloc. Signed-off-by: Alwin Joshy <joshyalwin@gmail.com> Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au>
1 parent 98fcdbd commit 941fc73

File tree

2 files changed

+141
-156
lines changed

2 files changed

+141
-156
lines changed

tool/microkit/src/lib.rs

Lines changed: 105 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub mod sdf;
1010
pub mod sel4;
1111
pub mod util;
1212

13-
use sel4::{BootInfo, Config};
13+
use sel4::Config;
1414
use std::cmp::min;
1515
use std::fmt;
1616

@@ -288,6 +288,7 @@ impl DisjointMemoryRegion {
288288
pub struct KernelAllocation {
289289
pub untyped_cap_address: u64, // FIXME: possibly this is an object, not an int?
290290
pub phys_addr: u64,
291+
pub size: u64,
291292
}
292293

293294
pub struct UntypedAllocator {
@@ -343,16 +344,12 @@ pub struct ObjectAllocator {
343344
}
344345

345346
impl ObjectAllocator {
346-
pub fn new(kernel_boot_info: &BootInfo) -> ObjectAllocator {
347-
let mut untyped = Vec::new();
348-
for ut in kernel_boot_info.untyped_objects.iter() {
349-
if ut.is_device {
350-
// Kernel allocator can only allocate out of normal memory
351-
// device memory can't be used for kernel objects
352-
continue;
353-
}
354-
untyped.push(UntypedAllocator::new(*ut, 0, vec![]));
355-
}
347+
pub fn new(untyped_pool: Vec<&UntypedObject>) -> ObjectAllocator {
348+
let mut untyped: Vec<UntypedAllocator> = untyped_pool
349+
.into_iter()
350+
.map(|ut| UntypedAllocator::new(*ut, 0, vec![]))
351+
.collect();
352+
untyped.sort_by(|a, b| a.untyped_object.base().cmp(&b.untyped_object.base()));
356353

357354
ObjectAllocator {
358355
allocation_idx: 0,
@@ -367,15 +364,17 @@ impl ObjectAllocator {
367364
pub fn alloc_n(&mut self, size: u64, count: u64) -> KernelAllocation {
368365
assert!(util::is_power_of_two(size));
369366
assert!(count > 0);
367+
let mem_size = count * size;
370368
for ut in &mut self.untyped {
371369
// See if this fits
372370
let start = util::round_up(ut.base() + ut.allocation_point, size);
373-
if start + (count * size) <= ut.end() {
374-
ut.allocation_point = (start - ut.base()) + (count * size);
371+
if start + mem_size <= ut.end() {
372+
ut.allocation_point = (start - ut.base()) + mem_size;
375373
self.allocation_idx += 1;
376374
let allocation = KernelAllocation {
377375
untyped_cap_address: ut.untyped_object.cap,
378376
phys_addr: start,
377+
size: mem_size,
379378
};
380379
ut.allocations.push(allocation);
381380
return allocation;
@@ -384,4 +383,97 @@ impl ObjectAllocator {
384383

385384
panic!("Can't alloc of size {}, count: {} - no space", size, count);
386385
}
386+
387+
pub fn reserve(&mut self, alloc: (&UntypedObject, u64)) {
388+
for ut in &mut self.untyped {
389+
if *alloc.0 == ut.untyped_object {
390+
if ut.base() <= alloc.1 && alloc.1 <= ut.end() {
391+
ut.allocation_point = alloc.1 - ut.base();
392+
return;
393+
} else {
394+
panic!(
395+
"Allocation {:?} ({:x}) not in untyped region {:?}",
396+
alloc.0, alloc.1, ut.untyped_object
397+
);
398+
}
399+
}
400+
}
401+
402+
panic!(
403+
"Allocation {:?} ({:x}) not in any device untyped",
404+
alloc.0, alloc.1
405+
);
406+
}
407+
408+
pub fn find_fixed(
409+
&mut self,
410+
phys_addr: u64,
411+
size: u64,
412+
) -> Option<(Option<Vec<KernelAllocation>>, KernelAllocation)> {
413+
for ut in &mut self.untyped {
414+
/* Find the right untyped */
415+
if phys_addr >= ut.base() && phys_addr < ut.end() {
416+
if phys_addr < ut.base() + ut.allocation_point {
417+
panic!("Error: physical address {:x} is below watermark", phys_addr);
418+
}
419+
420+
let space_left = ut.end() - (ut.base() + ut.allocation_point);
421+
if space_left < size {
422+
panic!(
423+
"Error: allocation for physical address {:x}
424+
is too large ({:x}) for untyped",
425+
phys_addr, size
426+
);
427+
}
428+
429+
let mut watermark = ut.base() + ut.allocation_point;
430+
let mut allocations: Option<Vec<KernelAllocation>>;
431+
432+
if phys_addr != watermark {
433+
allocations = Some(Vec::new());
434+
/* If the watermark isn't at the right place, we need to pad */
435+
let mut padding_required = phys_addr - watermark;
436+
// We are restricted in how much we can pad:
437+
// 1: Untyped objects must be power-of-two sized.
438+
// 2: Untyped objects must be aligned to their size.
439+
let mut padding_sizes = Vec::new();
440+
// We have two potential approaches for how we pad.
441+
// 1: Use largest objects possible respecting alignment
442+
// and size restrictions.
443+
// 2: Use a fixed size object multiple times. This will
444+
// create more objects, but as same sized objects can be
445+
// create in a batch, required fewer invocations.
446+
// For now we choose #1
447+
while padding_required > 0 {
448+
let wm_lsb = util::lsb(watermark);
449+
let sz_msb = util::msb(padding_required);
450+
let pad_object_size = 1 << min(wm_lsb, sz_msb);
451+
padding_sizes.push(pad_object_size);
452+
453+
allocations.as_mut().unwrap().push(KernelAllocation {
454+
untyped_cap_address: ut.untyped_object.cap,
455+
phys_addr: watermark,
456+
size: pad_object_size,
457+
});
458+
459+
watermark += pad_object_size;
460+
padding_required -= pad_object_size;
461+
}
462+
} else {
463+
allocations = None;
464+
}
465+
466+
let obj = KernelAllocation {
467+
untyped_cap_address: ut.untyped_object.cap,
468+
phys_addr: watermark,
469+
size,
470+
};
471+
472+
ut.allocation_point = (watermark + size) - ut.base();
473+
return Some((allocations, obj));
474+
}
475+
}
476+
477+
None
478+
}
387479
}

0 commit comments

Comments
 (0)