WIP: buddy allocator

This commit is contained in:
Jeremy Soller
2020-09-07 21:05:04 -06:00
parent 011212905d
commit d752c5c91e
3 changed files with 132 additions and 25 deletions
+8 -3
View File
@@ -96,11 +96,16 @@ impl Arch for EmulateArch {
}
const MEMORY_SIZE: usize = 64 * MEGABYTE;
static MEMORY_AREAS: [MemoryArea; 1] = [
static MEMORY_AREAS: [MemoryArea; 2] = [
MemoryArea {
base: PhysicalAddress::new(EmulateArch::PAGE_SIZE * 4), // Initial PML4, PDP, PD, and PT wasted
size: MEMORY_SIZE - EmulateArch::PAGE_SIZE * 4,
}
size: MEMORY_SIZE/2 - EmulateArch::PAGE_SIZE * 4,
},
// Second area for debugging
MemoryArea {
base: PhysicalAddress::new(MEMORY_SIZE/2),
size: MEMORY_SIZE/2,
},
];
static mut MACHINE: Option<Machine<EmulateArch>> = None;
+1
View File
@@ -61,6 +61,7 @@ impl VirtualAddress {
}
}
#[derive(Debug)]
pub struct MemoryArea {
pub base: PhysicalAddress,
pub size: usize,
+123 -22
View File
@@ -12,7 +12,10 @@ use rmm::{
VirtualAddress,
};
use core::marker::PhantomData;
use core::{
marker::PhantomData,
mem,
};
pub fn format_size(size: usize) -> String {
if size >= 2 * TERABYTE {
@@ -187,6 +190,104 @@ impl<A: Arch> SlabAllocator<A> {
}
}
#[derive(Clone, Copy, Debug)]
#[repr(packed)]
pub struct BuddyEntry {
pub base: PhysicalAddress,
pub size: usize,
pub map_phys: PhysicalAddress,
pub map_virt: VirtualAddress,
}
impl BuddyEntry {
pub fn empty() -> Self {
Self {
base: PhysicalAddress::new(0),
size: 0,
map_phys: PhysicalAddress::new(0),
map_virt: VirtualAddress::new(0),
}
}
}
pub struct BuddyAllocator<A> {
table_phys: PhysicalAddress,
table_virt: VirtualAddress,
phantom: PhantomData<A>,
}
impl<A: Arch> BuddyAllocator<A> {
pub unsafe fn new(areas: &'static [MemoryArea], offset: usize) -> Option<Self> {
// First, we need an allocator, so we can allocate the buddy tables
// Since the tables are static, we can use the bump allocator
let mut bump_allocator = BumpAllocator::<A>::new(areas, offset);
// Allocate buddy table
let table_phys = bump_allocator.allocate()?;
let table_virt = A::phys_to_virt(table_phys);
for i in 0 .. (A::PAGE_SIZE / mem::size_of::<BuddyEntry>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry>());
A::write(virt, BuddyEntry::empty());
}
let mut allocator = Self {
table_phys,
table_virt,
phantom: PhantomData,
};
// Add areas to buddy table, combining areas when possible
for area in areas.iter() {
for i in 0 .. (A::PAGE_SIZE / mem::size_of::<BuddyEntry>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry>());
let mut entry = A::read::<BuddyEntry>(virt);
let inserted = if area.base.add(area.size) == entry.base {
// Combine entry at start
entry.base = area.base;
entry.size += area.size;
true
} else if area.base == entry.base.add(entry.size) {
// Combine entry at end
entry.size += area.size;
true
} else if entry.size == 0 {
// Create new entry
entry.base = area.base;
entry.size = area.size;
true
} else {
false
};
if inserted {
A::write(virt, entry);
break;
}
}
}
//TODO: sort areas?
//TODO: Allocate buddy maps
for i in 0 .. (A::PAGE_SIZE / mem::size_of::<BuddyEntry>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry>());
let mut entry = A::read::<BuddyEntry>(virt);
if entry.size > 0 {
println!("{}: {:X?}", i, entry);
let pages = entry.size / A::PAGE_SIZE;
println!(" pages: {}", pages);
let map_size = (pages + 7) / 8;
println!(" map size: {}", format_size(map_size));
}
}
//TODO: mark areas used for static tables as used
Some(allocator)
}
}
pub struct Mapper<A> {
table_addr: PhysicalAddress,
allocator: BumpAllocator<A>,
@@ -262,27 +363,27 @@ unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
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()));
let mut allocator = BuddyAllocator::<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>() {