Add WIP slab allocator

This commit is contained in:
Jeremy Soller
2020-09-07 20:01:40 -06:00
parent d450cafad6
commit 011212905d
2 changed files with 142 additions and 6 deletions
-1
View File
@@ -226,7 +226,6 @@ impl<A: Arch> Machine<A> {
if f & A::ENTRY_FLAG_PRESENT == 0 { continue; }
// Page
let a = e & A::ENTRY_ADDRESS_MASK;
let page =
(i4 << 39) |
(i3 << 30) |
+142 -5
View File
@@ -53,10 +53,10 @@ pub struct BumpAllocator<A> {
}
impl<A: Arch> BumpAllocator<A> {
pub fn new(areas: &'static [MemoryArea]) -> Self {
pub fn new(areas: &'static [MemoryArea], offset: usize) -> Self {
Self {
areas,
offset: 0,
offset,
phantom: PhantomData,
}
}
@@ -74,6 +74,119 @@ impl<A: Arch> BumpAllocator<A> {
}
}
pub struct SlabNode<A> {
next: PhysicalAddress,
count: usize,
phantom: PhantomData<A>,
}
impl<A: Arch> SlabNode<A> {
pub fn new(next: PhysicalAddress, count: usize) -> Self {
Self {
next,
count,
phantom: PhantomData,
}
}
pub fn empty() -> Self {
Self::new(PhysicalAddress::new(0), 0)
}
pub unsafe fn insert(&mut self, phys: PhysicalAddress) {
let virt = A::phys_to_virt(phys);
A::write(virt, self.next);
self.next = phys;
self.count += 1;
}
pub unsafe fn remove(&mut self) -> Option<PhysicalAddress> {
if self.count > 0 {
let phys = self.next;
let virt = A::phys_to_virt(phys);
self.next = A::read(virt);
self.count -= 1;
Some(phys)
} else {
None
}
}
}
pub struct SlabAllocator<A> {
//TODO: Allow allocations up to maximum pageable size
nodes: [SlabNode<A>; 4],
phantom: PhantomData<A>,
}
impl<A: Arch> SlabAllocator<A> {
pub unsafe fn new(areas: &'static [MemoryArea], offset: usize) -> Self {
let mut allocator = Self {
nodes: [
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
],
phantom: PhantomData,
};
// Add unused areas to free lists
let mut area_offset = offset;
for area in areas.iter() {
if area_offset < area.size {
area_offset = 0;
let area_base = area.base.add(offset);
let area_size = area.size - offset;
allocator.free(area_base, area_size);
} else {
area_offset -= area.size;
}
}
allocator
}
pub unsafe fn allocate(&mut self, size: usize) -> Option<PhysicalAddress> {
for level in 0..A::PAGE_LEVELS - 1 {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
if size <= level_size {
if let Some(base) = self.nodes[level].remove() {
self.free(base.add(size), level_size - size);
return Some(base);
}
}
}
None
}
//TODO: This causes fragmentation, since neighbors are not identified
//TODO: remainders less than PAGE_SIZE will be lost
pub unsafe fn free(&mut self, mut base: PhysicalAddress, mut size: usize) {
for level in (0..A::PAGE_LEVELS - 1).rev() {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
while size >= level_size {
println!("Add {:X} {}", base.data(), format_size(level_size));
self.nodes[level].insert(base);
base = base.add(level_size);
size -= level_size;
}
}
}
pub unsafe fn remaining(&mut self) -> usize {
let mut remaining = 0;
for level in (0..A::PAGE_LEVELS - 1).rev() {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
remaining += self.nodes[level].count * level_size;
}
remaining
}
}
pub struct Mapper<A> {
table_addr: PhysicalAddress,
allocator: BumpAllocator<A>,
@@ -127,7 +240,7 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
println!("Memory: {}", format_size(size));
// Create a basic allocator for the first pages
let allocator = BumpAllocator::<A>::new(areas);
let allocator = BumpAllocator::<A>::new(areas, 0);
// Map all physical areas at PHYS_OFFSET
let mut mapper = Mapper::new(allocator).expect("failed to create Mapper");
@@ -142,10 +255,34 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
}
}
// Use the new table
A::set_table(mapper.table_addr);
let used = mapper.allocator.offset;
println!("Used: {}", format_size(used));
// Create the physical memory map
let offset = mapper.allocator.offset;
println!("Permanently used: {}", format_size(offset));
let mut allocator = SlabAllocator::<A>::new(areas, offset);
for i in 0..16 {
let phys_opt = allocator.allocate(4 * KILOBYTE);
println!("4 KB page {}: {:X?}", i, phys_opt);
if i % 2 == 0 {
if let Some(phys) = phys_opt {
allocator.free(phys, 4 * KILOBYTE);
}
}
}
for i in 0..16 {
let phys_opt = allocator.allocate(2 * MEGABYTE);
println!("2 MB page {}: {:X?}", i, phys_opt);
if i % 2 == 0 {
if let Some(phys) = phys_opt {
allocator.free(phys, 2 * MEGABYTE);
}
}
}
println!("Remaining: {}", format_size(allocator.remaining()));
}
unsafe fn inner<A: Arch>() {