[wip] Add boot memory regions info
This commit is contained in:
parent
3f98cbe8ec
commit
119017c703
|
@ -0,0 +1,128 @@
|
|||
#[derive(Default, Copy, Clone)]
|
||||
struct BootInfoMemRegion {
|
||||
pub start: PhysAddr,
|
||||
pub end: PhysAddr,
|
||||
}
|
||||
|
||||
impl BootInfoMemRegion {
|
||||
pub const fn new() -> BootInfoMemRegion {
|
||||
BootInfoMemRegion {
|
||||
start: PhysAddr::zero(),
|
||||
end: PhysAddr::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.end - self.start
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.start == self.end
|
||||
}
|
||||
}
|
||||
|
||||
const NUM_MEM_REGIONS: usize = 16;
|
||||
|
||||
pub enum BootInfoError {
|
||||
NoFreeMemRegions,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BootInfo {
|
||||
pub regions: [BootInfoMemRegion; NUM_MEM_REGIONS],
|
||||
pub max_slot_pos: usize,
|
||||
}
|
||||
|
||||
impl BootInfo {
|
||||
pub const fn new() -> BootInfo {
|
||||
BootInfo {
|
||||
regions: [BootInfoMemRegion::new(); NUM_MEM_REGIONS],
|
||||
max_slot_pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_region(&mut self, reg: BootInfoMemRegion) -> Result<(), BootInfoError> {
|
||||
if reg.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
assert!(reg.start <= reg.end);
|
||||
for region in self.regions.iter_mut() {
|
||||
if region.is_empty() {
|
||||
*region = reg;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
return Err(BootInfoError::NoFreeMemRegions);
|
||||
}
|
||||
|
||||
pub fn alloc_region(&mut self, size_bits: usize) -> Result<PhysAddr, BootInfoError> {
|
||||
let mut reg_index: usize = 0;
|
||||
let mut reg: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
let mut rem_small: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
let mut rem_large: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
/*
|
||||
* Search for a free mem region that will be the best fit for an allocation. We favour allocations
|
||||
* that are aligned to either end of the region. If an allocation must split a region we favour
|
||||
* an unbalanced split. In both cases we attempt to use the smallest region possible. In general
|
||||
* this means we aim to make the size of the smallest remaining region smaller (ideally zero)
|
||||
* followed by making the size of the largest remaining region smaller.
|
||||
*/
|
||||
for (i, reg_iter) in self.regions.iter().enumerate() {
|
||||
let mut new_reg: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
|
||||
/* Determine whether placing the region at the start or the end will create a bigger left over region */
|
||||
if reg_iter.start.align_up(1u64 << size_bits) - reg_iter.start
|
||||
< reg_iter.end - reg_iter.end.align_down(1u64 << size_bits)
|
||||
{
|
||||
new_reg.start = reg_iter.start.align_up(1u64 << size_bits);
|
||||
new_reg.end = new_reg.start + (1u64 << size_bits);
|
||||
} else {
|
||||
new_reg.end = reg_iter.end.align_down(1u64 << size_bits);
|
||||
new_reg.start = new_reg.end - (1u64 << size_bits);
|
||||
}
|
||||
if new_reg.end > new_reg.start
|
||||
&& new_reg.start >= reg_iter.start
|
||||
&& new_reg.end <= reg_iter.end
|
||||
{
|
||||
let mut new_rem_small: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
let mut new_rem_large: BootInfoMemRegion = BootInfoMemRegion::new();
|
||||
|
||||
if new_reg.start - reg_iter.start < reg_iter.end - new_reg.end {
|
||||
new_rem_small.start = reg_iter.start;
|
||||
new_rem_small.end = new_reg.start;
|
||||
new_rem_large.start = new_reg.end;
|
||||
new_rem_large.end = reg_iter.end;
|
||||
} else {
|
||||
new_rem_large.start = reg_iter.start;
|
||||
new_rem_large.end = new_reg.start;
|
||||
new_rem_small.start = new_reg.end;
|
||||
new_rem_small.end = reg_iter.end;
|
||||
}
|
||||
if reg.is_empty()
|
||||
|| (new_rem_small.size() < rem_small.size())
|
||||
|| (new_rem_small.size() == rem_small.size()
|
||||
&& new_rem_large.size() < rem_large.size())
|
||||
{
|
||||
reg = new_reg;
|
||||
rem_small = new_rem_small;
|
||||
rem_large = new_rem_large;
|
||||
reg_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if reg.is_empty() {
|
||||
panic!("Kernel init failed: not enough memory\n");
|
||||
}
|
||||
/* Remove the region in question */
|
||||
self.regions[reg_index] = BootInfoMemRegion::new();
|
||||
/* Add the remaining regions in largest to smallest order */
|
||||
self.insert_region(rem_large);
|
||||
if self.insert_region(rem_small).is_err() {
|
||||
println!("BootInfo::alloc_region(): wasted {} bytes due to alignment, try to increase NUM_MEM_REGIONS", rem_small.size());
|
||||
}
|
||||
Ok(reg.start)
|
||||
}
|
||||
}
|
||||
|
||||
#[link_section = ".data.boot"] // @todo put zero-initialized stuff to .bss.boot!
|
||||
static BOOT_INFO: sync::NullLock<BootInfo> = sync::NullLock::new(BootInfo::new());
|
|
@ -32,6 +32,7 @@ use architecture_not_supported_sorry;
|
|||
#[macro_use]
|
||||
pub mod arch;
|
||||
pub use arch::*;
|
||||
mod boot_info;
|
||||
mod devices;
|
||||
mod macros;
|
||||
mod mm;
|
||||
|
|
Loading…
Reference in New Issue