This commit is contained in:
2024-06-10 23:57:38 +03:00
parent 6de42c3dba
commit 1b2dd2bfbe
21 changed files with 1066 additions and 31 deletions

View 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
View 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,
}
}
}