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) {} }