Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Commit

Permalink
Corrected all compiler errors in the PMM (and fought the borrow check…
Browse files Browse the repository at this point in the history
…er all along the way!!!)
  • Loading branch information
mdpatelcsecon committed Feb 8, 2024
1 parent 8b36997 commit eeb6486
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 65 deletions.
6 changes: 0 additions & 6 deletions charlotte_core/src/arch/x86_64/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
mod pmm;
mod vmm;

use crate::bootinfo;

use core::arch::x86_64::__cpuid_count;
use lazy_static::lazy_static;

Expand All @@ -26,9 +24,5 @@ lazy_static! {
let vsig_bits = (cpuid.eax >> 8) & 0xFF;
vsig_bits as u8
};
///This value represents the base virtual address of the direct mapping of physical memory into
/// kernelspace. It should have the desired physical address added to it and then be cast to a
/// pointer to access the desired physical address.
pub static ref HHDM_BASE: u64 = bootinfo::HHDM_REQUEST.get_response().unwrap().offset();
}

121 changes: 62 additions & 59 deletions charlotte_core/src/arch/x86_64/memory/pmm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
//! The PFA can be used to allocate and deallocate frames for use by the kernel and user-space applications.
//! It is capable of allocating and deallocating contiguous blocks of frames, which is useful for things like
//! DMA and certain optimization techniques.
//! The direct memory map interface provides a means for safely accessing physical memory via a direct mapping
//! region. It is located in its own module and is documented there.
use core::borrow::{Borrow, BorrowMut};
use core::mem;
use core::{mem, result};
use core::slice::sort::quicksort;
use core::slice::SliceIndex;

use crate::access_control::CapabilityId;
use crate::bootinfo;
Expand All @@ -27,12 +25,13 @@ lazy_static! {
/// pointer to access the desired physical address.
/// Physical addresses should only ever be used while this Mutex is locked.
/// TODO: Find a way to make this Mutex more fine-grained and function more like a read-write lock on the physical memory.
pub static ref HHDM_BASE: TicketMutex<u64> = TicketMutex::new(bootinfo::HHDM_REQUEST.get_response().unwrap().offset());
pub static ref HHDM_BASE: TicketMutex<usize> = TicketMutex::new(bootinfo::HHDM_REQUEST.get_response().unwrap().offset() as usize);

///The physical frame allocator to be used by the kernel and user-space applications.
pub static ref PFA: TicketMutex<PhysicalFrameAllocator> = TicketMutex::new(PhysicalFrameAllocator::new());
}

#[derive(Debug)]
pub enum Error {
InsufficientMemory,
InsufficientContiguousMemory,
Expand All @@ -44,6 +43,7 @@ pub enum Error {
/// It is identical to the defines used by Limine with the exception of PfaReserved, which is used to represent
/// regions of physical memory that are reserved for use by the PFA itself and PfaNull, which is used to represent
/// region descriptors that are not in use.
#[derive(Clone, PartialEq, Eq)]
pub enum PhysicalMemoryType {
Usable,
Reserved,
Expand Down Expand Up @@ -88,6 +88,7 @@ impl PhysicalMemoryRegion {
}

/// The physical frame allocator is responsible for managing and allocating physical memory frames.
pub struct PhysicalFrameAllocator {
region_array_base: usize, // physical base address of the array of physical memory regions
region_array_len: usize, // number of elements in the array of physical memory regions
Expand All @@ -114,7 +115,7 @@ impl PhysicalFrameAllocator {
};
let init_region_array_len = Self::detect_total_frames(memory_map) / ALLOCATION_FACTOR;
if init_region_array_len
> largest_usable_region.length / mem::size_of::<PhysicalMemoryRegion>()
> largest_usable_region.length as usize / mem::size_of::<PhysicalMemoryRegion>()
{
panic!("No linear memory region large enough to hold the initial phyiscal memory region array");
}
Expand All @@ -133,21 +134,21 @@ impl PhysicalFrameAllocator {
fn detect_total_frames(memory_map: &[&Entry]) -> usize {
let mut total_memory = 0;
for entry in memory_map {
if entry.region_type != EntryType::BadMemory {
total_memory += entry.region_length as usize;
if entry.entry_type != EntryType::BAD_MEMORY {
total_memory += entry.length as usize;
}
}
total_memory / 4096
}

/// Returns the largest usable memory region in the memory map.
fn get_largest_usable_region(memory_map: &[&Entry]) -> Option<&'static Entry> {
fn get_largest_usable_region(memory_map: &'static [&Entry]) -> Option<&'static Entry> {
let mut largest_usable_region: Option<&Entry> = None;
for entry in memory_map {
if entry.entry_type == EntryType::Usable {
if entry.entry_type == EntryType::USABLE {
match largest_usable_region {
Some(lur) => {
if entry.region_length > lur.region_length {
if entry.length > lur.length {
largest_usable_region = Some(entry);
}
}
Expand All @@ -163,14 +164,14 @@ impl PhysicalFrameAllocator {
/// Returns the physical memory region array as a slice.
unsafe fn get_region_array(&self) -> &[PhysicalMemoryRegion] {
core::slice::from_raw_parts(
(self.region_array_base + *(HHDM_BASE.borrow())) as *const PhysicalMemoryRegion,
(self.region_array_base + *HHDM_BASE.lock()) as *const PhysicalMemoryRegion,
self.region_array_len,
)
}
/// Returns the physical memory region array as a mutable slice.
unsafe fn get_mut_region_array(&self) -> &mut [PhysicalMemoryRegion] {
unsafe fn get_mut_region_array(&mut self) -> &mut [PhysicalMemoryRegion] {
core::slice::from_raw_parts_mut(
(self.region_array_base + *(HHDM_BASE.borrow_mut())) as *mut PhysicalMemoryRegion,
(self.region_array_base + *HHDM_BASE.lock()) as *mut PhysicalMemoryRegion,
self.region_array_len,
)
}
Expand All @@ -183,28 +184,28 @@ impl PhysicalFrameAllocator {
}

let mut region_array = unsafe { self.get_mut_region_array() };
for (i, entry) in memory_map.enumerate() {
if entry.region_type != EntryType::BadMemory {
//initialize the region array using the memory map
for (i, entry) in memory_map.iter().enumerate() {
if entry.entry_type != EntryType::BAD_MEMORY {
region_array[i] = PhysicalMemoryRegion {
capability: None,
base: entry.base as usize,
n_frames: entry.length / 4096 as usize,
region_type: match entry.region_type {
EntryType::Usable => PhysicalMemoryType::Usable,
EntryType::Reserved => PhysicalMemoryType::Reserved,
EntryType::AcpiReclaimable => PhysicalMemoryType::AcpiReclaimable,
EntryType::AcpiNvs => PhysicalMemoryType::AcpiNvs,
EntryType::BootloaderReclaimable => {
PhysicalMemoryType::BootloaderReclaimable
}
EntryType::KernelAndModules => PhysicalMemoryType::KernelAndModules,
EntryType::FrameBuffer => PhysicalMemoryType::FrameBuffer,
n_frames: entry.length as usize / 4096,
region_type: match entry.entry_type {
EntryType::USABLE => PhysicalMemoryType::Usable,
EntryType::RESERVED => PhysicalMemoryType::Reserved,
EntryType::ACPI_RECLAIMABLE => PhysicalMemoryType::AcpiReclaimable,
EntryType::ACPI_NVS => PhysicalMemoryType::AcpiNvs,
EntryType::BOOTLOADER_RECLAIMABLE => PhysicalMemoryType::BootloaderReclaimable,
EntryType::KERNEL_AND_MODULES => PhysicalMemoryType::KernelAndModules,
EntryType::FRAMEBUFFER => PhysicalMemoryType::FrameBuffer,
_ => PhysicalMemoryType::BadMemory,
},
};
}
}
for i in memory_map.len()..self.region_array_len {
//initialize the rest of the region array with null descriptors
for i in memory_map.len()..region_array.len() {
region_array[i] = PhysicalMemoryRegion {
capability: None,
base: 0,
Expand All @@ -213,35 +214,33 @@ impl PhysicalFrameAllocator {
};
}
// add the region that represents the physical memory region array itself
let pmm_region = PhysicalMemoryRegion {
let pfa_region = PhysicalMemoryRegion {
capability: None,
base: self.region_array_base,
n_frames: self.region_array_len,
base: region_array.as_ptr() as usize - *HHDM_BASE.lock(), // this is here because borrowing rules prevent us from using self.region_array_base
n_frames: region_array.len(),
region_type: PhysicalMemoryType::PfaReserved,
};
for region in region_array.iter() {
for region in region_array.iter_mut() {
if region.region_type == PhysicalMemoryType::PfaNull {
*region = pmm_region;
*region = pfa_region;
break;
}
}
// Correct the region array
self.merge_and_sort_region_array();
// Merge adjacent regions of the same type and sort the region array by base address
Self::merge_and_sort_region_array(region_array);
}

/// Merge adjacent regions of the same type and sort the region array by base address.
fn merge_and_sort_region_array(&mut self) {
let mut region_array = unsafe { self.get_mut_region_array() };

fn merge_and_sort_region_array(region_array: &mut [PhysicalMemoryRegion]) {
//Merge adjacent regions of the same type
'array_loop: for i in 0..self.region_array_len {
'array_loop: for i in 0..region_array.len() {
//find the next non-null region
let mut next_nonnull_index = i + 1;
while region_array[next_nonnull_index].region_type == PhysicalMemoryType::PfaNull {
next_nonnull_index += 1;
}
//if there are no more non-null regions, break
if next_nonnull_index == self.region_array_len {
if next_nonnull_index == region_array.len() {
break 'array_loop;
}
//if the current region and the next region are of the same type, not null, and adjacent, merge them
Expand All @@ -257,13 +256,12 @@ impl PhysicalFrameAllocator {
quicksort(region_array, &PhysicalMemoryRegion::is_less);
}

fn append_region(&mut self, region: PhysicalMemoryRegion) -> Result<(), Error> {
let mut region_array = unsafe { self.get_mut_region_array() };
for i in 0..self.region_array_len {
fn append_region(region_array: &mut [PhysicalMemoryRegion], region: PhysicalMemoryRegion) -> Result<(), Error> {
for i in 0..region_array.len() {
if region_array[i].region_type == PhysicalMemoryType::PfaNull {
region_array[i] = region;
self.merge_and_sort_region_array();
Ok(())
Self::merge_and_sort_region_array(region_array);
return Ok(());
}
}
Err(Error::PfaRegionArrayFull)
Expand All @@ -272,26 +270,31 @@ impl PhysicalFrameAllocator {
/// Allocate a contiguous block of physical memory frames.
pub fn allocate_frames(&mut self, n_frames: usize, capability: Option<CapabilityId>) -> Result<PhysicalMemoryRegion, Error> {
let mut region_array = unsafe { self.get_mut_region_array() };
let mut allocated_region = Option::<PhysicalMemoryRegion>::None;

for region in region_array.iter_mut() {
if region.region_type == PhysicalMemoryType::Usable && region.n_frames >= n_frames {
//Create the descriptor for the newly allocated region
let mut allocated_region = PhysicalMemoryRegion {
capability: capability,
base: region.base,
n_frames,
region_type: PhysicalMemoryType::Allocated,
};
//Add the allocated region descriptor to the region array
//This also merges adjacent regions of the same type and sorts the region array
self.append_region(allocated_region.clone())?;
allocated_region = Some (
PhysicalMemoryRegion {
capability: capability,
base: region.base,
n_frames,
region_type: PhysicalMemoryType::Allocated,
}
);
//Update the region descriptor for the region that was allocated from
region.base += n_frames * 4096;
region.n_frames -= n_frames;

Ok(allocated_region)
}
}
Err(Error::InsufficientContiguousMemory)
match allocated_region {
Some(ar) => {
Self::append_region(region_array, ar.clone())?;
Ok(ar)
}
None => Err(Error::InsufficientContiguousMemory),
}
}
/// Deallocate a previously allocated contiguous block of physical memory frames.
pub fn deallocate_frames(&mut self, region: PhysicalMemoryRegion) -> Result<(), Error> {
Expand All @@ -300,8 +303,8 @@ impl PhysicalFrameAllocator {
if r.base == region.base && r.n_frames == region.n_frames {
r.region_type = PhysicalMemoryType::Usable;
r.capability = None;
self.merge_and_sort_region_array();
Ok(())
Self::merge_and_sort_region_array(region_array);
return Ok(());
}
}
Err(Error::AllocatedRegionNotFound)
Expand Down

0 comments on commit eeb6486

Please sign in to comment.