[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]
|
#[macro_use]
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
pub use arch::*;
|
pub use arch::*;
|
||||||
|
mod boot_info;
|
||||||
mod devices;
|
mod devices;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod mm;
|
mod mm;
|
||||||
|
|
Loading…
Reference in New Issue