use alloc::{vec, vec::Vec};
use core::mem::swap;
use crate::mm::kspace::kernel_loaded_offset;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum MemoryRegionType {
BadMemory = 0,
NonVolatileSleep = 1,
Reserved = 2,
Kernel = 3,
Module = 4,
Framebuffer = 5,
Reclaimable = 6,
Usable = 7,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct MemoryRegion {
base: usize,
len: usize,
typ: MemoryRegionType,
}
impl MemoryRegion {
pub fn new(base: usize, len: usize, typ: MemoryRegionType) -> Self {
MemoryRegion { base, len, typ }
}
pub fn kernel() -> Self {
extern "C" {
fn __kernel_start();
fn __kernel_end();
}
MemoryRegion {
base: __kernel_start as usize - kernel_loaded_offset(),
len: __kernel_end as usize - __kernel_start as usize,
typ: MemoryRegionType::Kernel,
}
}
pub fn base(&self) -> usize {
self.base
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn typ(&self) -> MemoryRegionType {
self.typ
}
pub fn truncate(&self, t: &MemoryRegion) -> Vec<MemoryRegion> {
if self.base < t.base {
if self.base + self.len > t.base {
if self.base + self.len > t.base + t.len {
vec![
MemoryRegion {
base: self.base,
len: t.base - self.base,
typ: self.typ,
},
MemoryRegion {
base: t.base + t.len,
len: self.base + self.len - (t.base + t.len),
typ: self.typ,
},
]
} else {
vec![MemoryRegion {
base: self.base,
len: t.base - self.base,
typ: self.typ,
}]
}
} else {
vec![*self]
}
} else if self.base < t.base + t.len {
if self.base + self.len > t.base + t.len {
vec![MemoryRegion {
base: t.base + t.len,
len: self.base + self.len - (t.base + t.len),
typ: self.typ,
}]
} else {
vec![]
}
} else {
vec![*self]
}
}
}
pub fn non_overlapping_regions_from(regions: &[MemoryRegion]) -> Vec<MemoryRegion> {
let mut regions_usable = Vec::<MemoryRegion>::new();
let mut regions_unusable = Vec::<MemoryRegion>::new();
for r in regions {
match r.typ {
MemoryRegionType::Usable | MemoryRegionType::Reclaimable => {
regions_usable.push(*r);
}
_ => {
regions_unusable.push(*r);
}
}
}
let mut regions = Vec::<MemoryRegion>::new();
let regions_src = &mut regions_usable;
let regions_dst = &mut regions;
for &r_unusable in ®ions_unusable {
regions_dst.clear();
for r_usable in &*regions_src {
regions_dst.append(&mut r_usable.truncate(&r_unusable));
}
swap(regions_src, regions_dst);
}
let mut all_regions = regions_unusable;
all_regions.append(&mut regions_usable);
all_regions
}