osiris/
mem.rs

1//! This module provides access to the global memory allocator.
2
3use crate::mem::pfa::PAGE_SIZE;
4use crate::mem::vmm::{AddressSpacelike, Backing, Perms, Region};
5use crate::sync::spinlock::SpinLocked;
6use alloc::Allocator;
7use core::ptr::NonNull;
8use hal::mem::PhysAddr;
9
10pub mod alloc;
11pub mod pfa;
12pub mod vmm;
13
14#[allow(dead_code)]
15pub const BITS_PER_PTR: usize = core::mem::size_of::<usize>() * 8;
16
17unsafe extern "C" {
18    unsafe static __stack_top: u8;
19}
20
21/// The global memory allocator.
22static GLOBAL_ALLOCATOR: SpinLocked<alloc::bestfit::BestFitAllocator> =
23    SpinLocked::new(alloc::bestfit::BestFitAllocator::new());
24
25/// Initialize the memory allocator.
26///
27/// `regions` - The memory node module of device tree codegen file.
28///
29/// Returns an error if the memory allocator could not be initialized.
30pub fn init_memory() -> vmm::AddressSpace {
31    let stack_top = &raw const __stack_top as usize;
32    if let Err(e) = pfa::init_pfa(PhysAddr::new(stack_top)) {
33        // TODO: Get this from the DeviceTree.
34        panic!("failed to initialize PFA. Error: {e}");
35    }
36
37    // TODO: Configure.
38    let pgs = 10;
39
40    let mut kaddr_space = vmm::AddressSpace::new(pgs).unwrap_or_else(|e| {
41        panic!("failed to create kernel address space. Error: {e}");
42    });
43
44    let begin = kaddr_space
45        .map(Region::new(
46            None,
47            2 * PAGE_SIZE,
48            Backing::Zeroed,
49            Perms::all(),
50        ))
51        .unwrap_or_else(|e| {
52            panic!("failed to map kernel address space. Error: {e}");
53        });
54
55    {
56        let mut allocator = GLOBAL_ALLOCATOR.lock();
57
58        let range = begin..(begin + pgs * PAGE_SIZE);
59        if let Err(e) = unsafe { allocator.add_range(&range) } {
60            panic!("failed to add range to allocator. Error: {e}");
61        }
62    }
63
64    kaddr_space
65}
66
67/// Allocate a memory block. Normally Box<T> or SizedPool<T> should be used instead of this function.
68///
69/// `size` - The size of the memory block to allocate.
70/// `align` - The alignment of the memory block.
71///
72/// Returns a pointer to the allocated memory block if the allocation was successful, or `None` if the allocation failed.
73pub fn malloc(size: usize, align: usize) -> Option<NonNull<u8>> {
74    let mut allocator = GLOBAL_ALLOCATOR.lock();
75    allocator.malloc(size, align, None).ok()
76}
77
78/// Free a memory block.
79///
80/// `ptr` - The pointer to the memory block.
81/// `size` - The size of the memory block.
82///
83/// # Safety
84///
85/// The caller must ensure that the pointer is from a previous call to `malloc` and that the size is still the same.
86pub unsafe fn free(ptr: NonNull<u8>, size: usize) {
87    let mut allocator = GLOBAL_ALLOCATOR.lock();
88    unsafe { allocator.free(ptr, size) };
89}
90
91/// Aligns a size to be a multiple of the u128 alignment.
92///
93/// `size` - The size to align.
94///
95/// Returns the aligned size.
96pub fn align_up(size: usize) -> usize {
97    if size >= (usize::MAX - align_of::<u128>()) {
98        return usize::MAX;
99    }
100
101    let align = align_of::<u128>();
102    (size + align - 1) & !(align - 1)
103}