- made improvements to memory code (refactored)
- started on improvements to the page frame allocator. it should be able to provide a usable page for any given virtual memory address requested.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use core::arch::x86_64::__cpuid;
|
||||
|
||||
use crate::arch::x86_64::memory::memory_map::PHYSICAL_MEMORY_OFFSET;
|
||||
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
|
||||
use crate::serial_print;
|
||||
use x86_64::{
|
||||
PhysAddr, VirtAddr,
|
||||
|
||||
@@ -2,20 +2,19 @@ use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ptr;
|
||||
use spin::{Mutex, MutexGuard};
|
||||
use x86_64::structures::paging::{Size4KiB, mapper::MapToError};
|
||||
use crate::arch::x86_64::memory::{HEAP_SIZE, HEAP_VIRTUAL_SPACE};
|
||||
|
||||
/// We are currently using a linked list heap allocator which uses our underlying page allocator.
|
||||
#[global_allocator]
|
||||
/// This is now Rust's global allocator, so we can use stuff requiring heap allocations.
|
||||
static ALLOCATOR: Locked<FoundryAllocator> = Locked::new(FoundryAllocator::new());
|
||||
|
||||
pub const HEAP_START: usize = 0x4444_4444_0000;
|
||||
pub const HEAP_SIZE: usize = 1024 * 1024 * 1024;
|
||||
|
||||
/// Sets up the heap using the backing page frame allocator.
|
||||
pub unsafe fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
||||
unsafe {
|
||||
// code to allocate frames is now done in the page fault interrupt handler!
|
||||
ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
|
||||
ALLOCATOR.lock().init(HEAP_VIRTUAL_SPACE, HEAP_SIZE);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -36,7 +35,7 @@ impl<T> Locked<T> {
|
||||
}
|
||||
}
|
||||
|
||||
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048];
|
||||
const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
|
||||
|
||||
struct ListNode {
|
||||
next: Option<&'static mut ListNode>,
|
||||
@@ -61,6 +60,11 @@ impl FoundryAllocator {
|
||||
fallback: Locked::new(FoundryFallbackAllocator::new()),
|
||||
}
|
||||
}
|
||||
/// Initializes the fallback allocator with the given heap start address and size.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because it does not check whether the given heap start address and size are valid.
|
||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||
unsafe {
|
||||
self.fallback.lock().init(heap_start, heap_size);
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod heap_alloc;
|
||||
pub mod stack_alloc;
|
||||
pub(crate) mod page_alloc;
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB};
|
||||
use limine::response::MemoryMapResponse;
|
||||
use spin::Mutex;
|
||||
use limine::memory_map::EntryType;
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
use x86_64::structures::paging::mapper::MapToError;
|
||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||
|
||||
pub struct FoundryOSFrameAllocator {
|
||||
memory_map: &'static MemoryMapResponse,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl FoundryOSFrameAllocator {
|
||||
/// Creates a new `FoundryOSFrameAllocator` from a memory map.
|
||||
///
|
||||
/// This function takes a reference to a `MemoryMapResponse` and initializes a
|
||||
/// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that
|
||||
/// the first frame to be allocated is the first frame in the memory map.
|
||||
pub fn init(memory_map: &'static MemoryMapResponse) {
|
||||
FRAME_ALLOCATOR.call_once(|| Mutex::new(Self {
|
||||
memory_map,
|
||||
next: 0,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn count_usable_frames(&self) -> u32 {
|
||||
self.usable_frames().count() as u32
|
||||
}
|
||||
|
||||
pub fn available_memory(&self) -> u64 {
|
||||
( self.memory_map.entries().len() * 4096 ) as u64 // multiply the number of physical frames by 4096 to get the memory size
|
||||
}
|
||||
|
||||
/// An iterator over all usable frames in the memory map.
|
||||
///
|
||||
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
|
||||
///
|
||||
/// This function is used to allocate frames for the pagemap.
|
||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
||||
let regions = self.memory_map.entries().iter();
|
||||
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
|
||||
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
|
||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn allocate_page(&mut self, start_addr: VirtAddr, flags: PageTableFlags) -> Result<(), MapToError<Size4KiB>> {
|
||||
let page = Page::from_start_address(start_addr).map_err(|_| MapToError::FrameAllocationFailed)?;
|
||||
let frame = self.allocate_frame().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
let _ = unsafe {
|
||||
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
||||
mapper.map_to(page, frame, flags, &mut *FRAME_ALLOCATOR.get().unwrap().lock())?
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
|
||||
/// Allocates a frame from the list of usable frames.
|
||||
///
|
||||
/// This function returns the next available `PhysFrame` from the memory map,
|
||||
/// if one exists. Once a frame is allocated, the internal counter is incremented
|
||||
/// to point to the next frame for future allocations.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `Some(PhysFrame)`: If a usable frame is available.
|
||||
/// - `None`: If there are no more usable frames to allocate.
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
let frame = self.usable_frames().nth(self.next);
|
||||
self.next += 1;
|
||||
frame
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
use x86_64::structures::paging::{mapper, FrameAllocator, Mapper, Page, Size4KiB};
|
||||
use x86_64::VirtAddr;
|
||||
use crate::arch::x86_64::memory::STACK_VIRTUAL_SPACE;
|
||||
|
||||
fn reserve_stack_memory(size_in_pages: u64) -> Page {
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
static STACK_ALLOC_NEXT: AtomicU64 = AtomicU64::new(0x_5555_5555_0000);
|
||||
static STACK_ALLOC_NEXT: AtomicU64 = AtomicU64::new(STACK_VIRTUAL_SPACE as u64);
|
||||
let start_addr = VirtAddr::new(STACK_ALLOC_NEXT.fetch_add(
|
||||
size_in_pages * Page::<Size4KiB>::SIZE,
|
||||
Ordering::Relaxed,
|
||||
@@ -12,17 +13,32 @@ fn reserve_stack_memory(size_in_pages: u64) -> Page {
|
||||
.expect("`STACK_ALLOC_NEXT` not page aligned")
|
||||
}
|
||||
|
||||
/// Allocates a stack in the virtual address space, mapped to physical pages.
|
||||
///
|
||||
/// This function allocates a stack in the virtual address space, mapped to physical pages.
|
||||
/// The stack is allocated as a sequence of pages, with the first page allocated as a guard page.
|
||||
/// The stack is then mapped to the allocated physical frame.
|
||||
///
|
||||
/// The function takes the size of the stack in pages, a mutable reference to a mapper, and a
|
||||
/// mutable reference to a frame allocator. It returns a `Result` containing a `StackBounds`
|
||||
/// struct, which contains the start and end virtual addresses of the allocated stack.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe because it maps physical frames to virtual addresses without any
|
||||
/// protection. This can lead to bugs if the physical frames are not correctly allocated, or if the
|
||||
/// virtual addresses are not correctly aligned.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the allocation of the physical frame fails.
|
||||
pub unsafe fn alloc_stack(
|
||||
size_in_pages: u64,
|
||||
mapper: &mut impl Mapper<Size4KiB>,
|
||||
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||
) -> Result<StackBounds, mapper::MapToError<Size4KiB>> { unsafe {
|
||||
use x86_64::structures::paging::PageTableFlags as Flags;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let guard_page = reserve_stack_memory(size_in_pages + 1);
|
||||
let stack_start = guard_page + 1;
|
||||
let stack_end = stack_start + size_in_pages;
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
pub mod allocation;
|
||||
pub mod memory_map;
|
||||
pub mod mapping;
|
||||
pub mod units;
|
||||
|
||||
// use lib_alloc::allocator::FoundryAllocator;
|
||||
use limine::{memory_map::EntryType, response::MemoryMapResponse};
|
||||
use spin::{Mutex, Once};
|
||||
use x86_64::{
|
||||
PhysAddr, VirtAddr,
|
||||
registers::control::Cr3,
|
||||
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
|
||||
registers::control::Cr3, structures::paging::{FrameAllocator, OffsetPageTable, PageTable}
|
||||
,
|
||||
VirtAddr,
|
||||
};
|
||||
use allocation::page_alloc::FoundryOSFrameAllocator;
|
||||
use units::MemoryUnits::*;
|
||||
|
||||
pub const STACK_VIRTUAL_SPACE: usize = 0x5555_5555_0000; // start address of the memory space where we store allocated stacks
|
||||
pub const HEAP_VIRTUAL_SPACE: usize = 0x4444_4444_0000; // start address of heap allocated memory
|
||||
pub const HEAP_SIZE: usize = MiB(1).to_bytes();
|
||||
|
||||
|
||||
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
|
||||
pub static OFFSET_PAGE_TABLE: Once<Mutex<OffsetPageTable>> = Once::new();
|
||||
@@ -53,56 +59,3 @@ pub fn init_page_table(physical_memory_offset: VirtAddr) {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FoundryOSFrameAllocator {
|
||||
memory_map: &'static MemoryMapResponse,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl FoundryOSFrameAllocator {
|
||||
/// Creates a new `FoundryOSFrameAllocator` from a memory map.
|
||||
///
|
||||
/// This function takes a reference to a `MemoryMapResponse` and initializes a
|
||||
/// `FoundryOSFrameAllocator` with it. The `next` field is set to 0, indicating that
|
||||
/// the first frame to be allocated is the first frame in the memory map.
|
||||
pub unsafe fn init(memory_map: &'static MemoryMapResponse) { unsafe {
|
||||
FRAME_ALLOCATOR.call_once(|| Mutex::new(Self {
|
||||
memory_map,
|
||||
next: 0,
|
||||
}));
|
||||
}}
|
||||
|
||||
pub fn count_usable_frames(&self) -> u32 {
|
||||
self.usable_frames().count() as u32
|
||||
}
|
||||
|
||||
/// An iterator over all usable frames in the memory map.
|
||||
///
|
||||
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
|
||||
///
|
||||
/// This function is used to allocate frames for the pagemap.
|
||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
||||
let regions = self.memory_map.entries().iter();
|
||||
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
|
||||
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
|
||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for FoundryOSFrameAllocator {
|
||||
/// Allocates a frame from the list of usable frames.
|
||||
///
|
||||
/// This function returns the next available `PhysFrame` from the memory map,
|
||||
/// if one exists. Once a frame is allocated, the internal counter is incremented
|
||||
/// to point to the next frame for future allocations.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `Some(PhysFrame)`: If a usable frame is available.
|
||||
/// - `None`: If there are no more usable frames to allocate.
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
let frame = self.usable_frames().nth(self.next);
|
||||
self.next += 1;
|
||||
frame
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
pub enum MemoryUnits {
|
||||
B(usize),
|
||||
KiB(usize),
|
||||
MiB(usize),
|
||||
GiB(usize),
|
||||
}
|
||||
|
||||
impl MemoryUnits {
|
||||
pub const fn to_bytes(&self) -> usize {
|
||||
match self {
|
||||
Self::B(b) => *b,
|
||||
Self::KiB(kib) => *kib * 1024,
|
||||
Self::MiB(mib) => *mib * 1024 * 1024,
|
||||
Self::GiB(gib) => *gib * 1024 * 1024 * 1024,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_bytes(bytes: usize) -> Self {
|
||||
if bytes < 1024 {
|
||||
Self::B(bytes)
|
||||
} else if bytes < 1024 * 1024 {
|
||||
Self::KiB(bytes / 1024)
|
||||
} else if bytes < 1024 * 1024 * 1024 {
|
||||
Self::MiB(bytes / (1024 * 1024))
|
||||
} else {
|
||||
Self::GiB(bytes / (1024 * 1024 * 1024))
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn convert(&mut self) {
|
||||
match self {
|
||||
Self::B(b) if *b > 1024 => *self = Self::KiB(*b / 1024),
|
||||
Self::KiB(kib) if *kib > 1024 => *self = Self::MiB(*kib / 1024),
|
||||
Self::MiB(mib) if *mib > 1024 => *self = Self::GiB(*mib / 1024),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for MemoryUnits {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::B(b) => write!(f, "{} B", b),
|
||||
Self::KiB(kib) => write!(f, "{} KiB", kib),
|
||||
Self::MiB(mib) => write!(f, "{} MiB", mib),
|
||||
Self::GiB(gib) => write!(f, "{} GiB", gib),
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -17,11 +17,11 @@ use crate::{
|
||||
prelude::*,
|
||||
};
|
||||
use arch::x86_64::memory::allocation::heap_alloc::init_heap;
|
||||
use arch::x86_64::memory::memory_map;
|
||||
use arch::x86_64::memory::mapping;
|
||||
use core::arch::asm;
|
||||
use limine::BaseRevision;
|
||||
use x86_64::VirtAddr;
|
||||
use crate::arch::x86_64::memory::FoundryOSFrameAllocator;
|
||||
use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
||||
|
||||
pub mod arch;
|
||||
pub mod resources;
|
||||
@@ -67,7 +67,7 @@ pub fn boot() -> Result<(), &'static str> {
|
||||
|
||||
use arch::x86_64::{gdt, interrupts};
|
||||
|
||||
let memory_map = memory_map::get_memory_map();
|
||||
let memory_map = mapping::get_memory_map();
|
||||
|
||||
print_log!(" Initialising Serial... ");
|
||||
if arch::x86_64::drivers::serial::init().is_err() {
|
||||
@@ -85,12 +85,12 @@ pub fn boot() -> Result<(), &'static str> {
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Initialising Memory Subsystem... ");
|
||||
let physical_memory_offset = VirtAddr::new(*memory_map::PHYSICAL_MEMORY_OFFSET);
|
||||
let physical_memory_offset = VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET);
|
||||
init_page_table(physical_memory_offset);
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Setting Up Page Table... ");
|
||||
unsafe { FoundryOSFrameAllocator::init(memory_map) };
|
||||
FoundryOSFrameAllocator::init(memory_map);
|
||||
println_log!("[Success]");
|
||||
|
||||
print_log!(" Initialising Heap... ");
|
||||
|
||||
Reference in New Issue
Block a user