use core::alloc::{GlobalAlloc, Layout};
use core::{mem, ptr};
use multiboot2::{BootInformation, BootInformationHeader};
use super::{Frame, PAGE_SIZE};
use crate::allocator::{HEAP_SIZE, HEAP_START, Locked};
pub struct AreaFrameAllocator {
next_free_frame: Frame,
kernel_start: Frame,
kernel_end: Frame,
multiboot_start: Frame,
multiboot_end: Frame,
}
impl AreaFrameAllocator {
pub const fn new() -> Self {
Self {
next_free_frame: Frame::new(),
kernel_start: Frame::new(),
kernel_end: Frame::new(),
multiboot_start: Frame::new(),
multiboot_end: Frame::new(),
}
}
pub unsafe fn init(&mut self, multiboot_information_address: usize) -> Self {
let boot_info = unsafe {
BootInformation::load(multiboot_information_address as *const BootInformationHeader)
.unwrap()
};
//let memory_map_tag = boot_info.memory_map_tag().expect("Memory map tag required");
let elf_sections_tag = boot_info
.elf_sections_tag()
.expect("Elf sections tag required");
let kernel_start = elf_sections_tag
.sections()
.map(|s| s.start_address())
.min()
.unwrap();
let kernel_end = elf_sections_tag
.sections()
.map(|s| s.end_address())
.max()
.unwrap();
let multiboot_start = multiboot_information_address;
let multiboot_end = multiboot_start + boot_info.total_size();
AreaFrameAllocator {
next_free_frame: Frame { number: 0 },
kernel_start: Frame {
number: kernel_start as usize,
},
kernel_end: Frame {
number: kernel_end as usize,
},
multiboot_start: Frame {
number: multiboot_start,
},
multiboot_end: Frame {
number: multiboot_end,
},
}
}
fn find_frame(&mut self, size: usize, align: usize) -> Option<(Frame, usize)> {
let next_addr = self.next_free_frame.number * PAGE_SIZE + HEAP_START;
if &next_addr + core::mem::align_of::() <= PAGE_SIZE + HEAP_START {
Some((Frame::containing_address(next_addr), next_addr))
} else {
None
}
}
fn size_align(layout: Layout) -> (usize, usize) {
let layout = layout
.align_to(mem::align_of::())
.expect("adjusting alignment failed")
.pad_to_align();
let size = layout.size().max(mem::align_of::());
(size, layout.align())
}
}
unsafe impl GlobalAlloc for Locked {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let (size, align) = AreaFrameAllocator::size_align(layout);
let mut allocator = self.lock();
match allocator.find_frame(size, align) {
Some((_, addr)) => addr as *mut u8,
None => ptr::null_mut(),
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {}
}