From d752c5c91e66c80e0d96b1a29fd0c3f3e651e6ff Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 7 Sep 2020 21:05:04 -0600 Subject: [PATCH] WIP: buddy allocator --- src/arch/emulate.rs | 11 +++- src/lib.rs | 1 + src/main.rs | 145 +++++++++++++++++++++++++++++++++++++------- 3 files changed, 132 insertions(+), 25 deletions(-) diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index 5106c4561d..e4ed0ce220 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -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> = None; diff --git a/src/lib.rs b/src/lib.rs index b34ed7e15b..cbd5f79462 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ impl VirtualAddress { } } +#[derive(Debug)] pub struct MemoryArea { pub base: PhysicalAddress, pub size: usize, diff --git a/src/main.rs b/src/main.rs index a331c3dfd5..1a3a6ca68c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 SlabAllocator { } } +#[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 { + table_phys: PhysicalAddress, + table_virt: VirtualAddress, + phantom: PhantomData, +} + +impl BuddyAllocator { + pub unsafe fn new(areas: &'static [MemoryArea], offset: usize) -> Option { + // 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::::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::()) { + let virt = table_virt.add(i * mem::size_of::()); + 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::()) { + let virt = table_virt.add(i * mem::size_of::()); + let mut entry = A::read::(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::()) { + let virt = table_virt.add(i * mem::size_of::()); + let mut entry = A::read::(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 { table_addr: PhysicalAddress, allocator: BumpAllocator, @@ -262,27 +363,27 @@ unsafe fn new_tables(areas: &'static [MemoryArea]) { let offset = mapper.allocator.offset; println!("Permanently used: {}", format_size(offset)); - let mut allocator = SlabAllocator::::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::::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() {