95 lines
3.1 KiB
Rust
95 lines
3.1 KiB
Rust
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::<Frame>() <= 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::<Frame>())
|
|
.expect("adjusting alignment failed")
|
|
.pad_to_align();
|
|
let size = layout.size().max(mem::align_of::<Frame>());
|
|
(size, layout.align())
|
|
}
|
|
}
|
|
|
|
unsafe impl GlobalAlloc for Locked<AreaFrameAllocator> {
|
|
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) {}
|
|
}
|