uwu
This commit is contained in:
86
kernel/src/mem/area_frame_alloc.rs
Normal file
86
kernel/src/mem/area_frame_alloc.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use core::slice::Iter;
|
||||
|
||||
use super::{Frame, FrameAllocator, MemInfo, MemoryAreaIter};
|
||||
use multiboot2::MemoryArea;
|
||||
|
||||
pub struct AreaFrameAllocator<'a> {
|
||||
next_free_frame: Frame,
|
||||
current_area: Option<&'a MemoryArea>,
|
||||
areas: MemoryAreaIter,
|
||||
kernel_start: Frame,
|
||||
kernel_end: Frame,
|
||||
multiboot_start: Frame,
|
||||
multiboot_end: Frame,
|
||||
}
|
||||
|
||||
impl<'a> FrameAllocator for AreaFrameAllocator<'a> {
|
||||
fn allocate_frame(&mut self) -> Option<Frame> {
|
||||
if let Some(area) = self.current_area {
|
||||
// "Clone" the frame to return it if it's free. Frame doesn't
|
||||
// implement Clone, but we can construct an identical frame.
|
||||
let frame = Frame{ number: self.next_free_frame.number };
|
||||
|
||||
// the last frame of the current area
|
||||
let current_area_last_frame = {
|
||||
let address = area.start_address() + area.size() - 1;
|
||||
Frame::containing_address(address as usize)
|
||||
};
|
||||
|
||||
if frame > current_area_last_frame {
|
||||
// all frames of current area are used, switch to next area
|
||||
self.choose_next_area();
|
||||
} else if frame >= self.kernel_start && frame <= self.kernel_end {
|
||||
// `frame` is used by the kernel
|
||||
self.next_free_frame = Frame {
|
||||
number: self.kernel_end.number + 1
|
||||
};
|
||||
} else if frame >= self.multiboot_start && frame <= self.multiboot_end {
|
||||
// `frame` is used by the multiboot information structure
|
||||
self.next_free_frame = Frame {
|
||||
number: self.multiboot_end.number + 1
|
||||
};
|
||||
} else {
|
||||
// frame is unused, increment `next_free_frame` and return it
|
||||
self.next_free_frame.number += 1;
|
||||
return Some(frame);
|
||||
}
|
||||
// `frame` was not valid, try it again with the updated `next_free_frame`
|
||||
self.allocate_frame()
|
||||
} else {
|
||||
None // no free frames left
|
||||
}
|
||||
}
|
||||
|
||||
fn deallocate_frame(&mut self, _: Frame) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AreaFrameAllocator<'a> {
|
||||
fn choose_next_area(&mut self) {
|
||||
self.current_area = self.areas.clone().filter(|area| {
|
||||
let address = area.start_address() + area.size() - 1;
|
||||
Frame::containing_address(address as usize) >= self.next_free_frame
|
||||
}).min_by_key(|area| area.start_address());
|
||||
|
||||
if let Some(area) = self.current_area {
|
||||
let start_frame = Frame::containing_address(area.start_address() as usize);
|
||||
if self.next_free_frame < start_frame {
|
||||
self.next_free_frame = start_frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn new(mi: MemInfo) -> AreaFrameAllocator<'a> {
|
||||
let mut allocator = AreaFrameAllocator {
|
||||
next_free_frame: Frame::containing_address(0),
|
||||
current_area: None,
|
||||
areas: mi.mem_area_iter,
|
||||
kernel_start: Frame::containing_address(mi.kernel_start),
|
||||
kernel_end: Frame::containing_address(mi.kernel_end),
|
||||
multiboot_start: Frame::containing_address(mi.mb_start),
|
||||
multiboot_end: Frame::containing_address(mi.mb_end),
|
||||
};
|
||||
allocator.choose_next_area();
|
||||
allocator
|
||||
}
|
||||
}
|
||||
115
kernel/src/mem/mod.rs
Normal file
115
kernel/src/mem/mod.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use core::{alloc::{GlobalAlloc, Layout}, ops::Deref};
|
||||
|
||||
use multiboot2::{BootInformation, BootInformationHeader, MemoryArea, MemoryAreaType, MemoryMapTag, TagTrait};
|
||||
|
||||
pub mod area_frame_alloc;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL_ALLOCATOR: DummyAlloc = DummyAlloc;
|
||||
pub struct DummyAlloc;
|
||||
unsafe impl GlobalAlloc for DummyAlloc {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 0 as *mut u8 }
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {}
|
||||
}
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Frame {
|
||||
number: usize,
|
||||
}
|
||||
|
||||
|
||||
impl Frame {
|
||||
fn containing_address(address: usize) -> Frame {
|
||||
Frame{ number: address / PAGE_SIZE }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FrameAllocator {
|
||||
fn allocate_frame(&mut self) -> Option<Frame>;
|
||||
fn deallocate_frame(&mut self, frame: Frame);
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MemoryAreaIter {
|
||||
current_area: *const MemoryArea,
|
||||
last_area: *const MemoryArea,
|
||||
entry_size: u32,
|
||||
}
|
||||
|
||||
impl Iterator for MemoryAreaIter {
|
||||
type Item = &'static MemoryArea;
|
||||
fn next(&mut self) -> Option<&'static MemoryArea> {
|
||||
if self.current_area > self.last_area {
|
||||
None
|
||||
} else {
|
||||
let area = unsafe{&*self.current_area};
|
||||
self.current_area = ((self.current_area as u32) + self.entry_size)
|
||||
as *const MemoryArea;
|
||||
if area.typ() == MemoryAreaType::Available {
|
||||
Some(area)
|
||||
} else {self.next()}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryAreaIter {
|
||||
pub fn new(mmap_tag: &MemoryMapTag) -> Self {
|
||||
let self_ptr = mmap_tag as *const MemoryMapTag;
|
||||
let start_area = (mmap_tag.memory_areas().first().unwrap()) as *const MemoryArea;
|
||||
MemoryAreaIter {
|
||||
current_area: start_area,
|
||||
last_area: ((self_ptr as *const () as usize) + mmap_tag.size() - mmap_tag.entry_size() as usize) as *const MemoryArea,
|
||||
entry_size: mmap_tag.entry_size(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemInfo{
|
||||
mem_area_iter: MemoryAreaIter,
|
||||
pub kernel_start: usize,
|
||||
pub kernel_end: usize,
|
||||
pub mb_start: usize,
|
||||
pub mb_end: usize,
|
||||
}
|
||||
|
||||
impl MemInfo {
|
||||
pub fn load(mb_ptr: usize) -> Self {
|
||||
let boot_info = unsafe {
|
||||
multiboot2::BootInformation::load(mb_ptr as *const BootInformationHeader).unwrap()
|
||||
};
|
||||
let mmap_tag = boot_info.memory_map_tag().unwrap().clone();
|
||||
|
||||
// log::debug!("Memory areas:");
|
||||
// for area in mmap_tag.memory_areas() {
|
||||
// log::debug!(" start: 0x{:x}, sz: 0x{:x}", area.start_address(), area.size());
|
||||
// }
|
||||
|
||||
// log::debug!("kernel sections:");
|
||||
// for section in boot_info.elf_sections().unwrap() {
|
||||
// log::debug!("{}: start: 0x{:x}, sz: 0x{:x}, flags: 0b{:b}", section.name().unwrap_or("NONE"),
|
||||
// section.start_address(), section.size(), section.flags());
|
||||
// }
|
||||
let kernel_start = boot_info.elf_sections().unwrap().clone().map(|s| s.start_address()).min().unwrap() as usize;
|
||||
let kernel_end = boot_info.elf_sections().unwrap().clone().map(|s| s.end_address()).max().unwrap() as usize;
|
||||
let mb_start = boot_info.start_address();
|
||||
let mb_end = boot_info.end_address();
|
||||
|
||||
//log::debug!("Kernel: start: 0x{:x} sz: 0x{:x}", mi.kernel_start, mi.kernel_end - mi.kernel_start);
|
||||
//log::debug!("Multiboot: start: 0x{:x} sz: 0x{:x}", mi.mb_start, mi.mb_end - mi.mb_start);
|
||||
|
||||
Self {
|
||||
mem_area_iter: MemoryAreaIter::new(mmap_tag),
|
||||
kernel_start,
|
||||
kernel_end,
|
||||
mb_start,
|
||||
mb_end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user