osiris/mem/
pfa.rs

1// The top level page frame allocator.
2
3use hal::mem::PhysAddr;
4
5use crate::error::Result;
6use crate::sync::spinlock::SpinLocked;
7use crate::types::boxed::Box;
8
9use core::pin::Pin;
10
11mod bitset;
12
13/// Page size constant (typically 4KB)
14pub const PAGE_SIZE: usize = 4096;
15
16const PAGE_CNT: usize = 100; // TODO: This should be determined by the DeviceTree.
17
18type AllocatorType = bitset::Allocator<PAGE_CNT>;
19
20static PFA: SpinLocked<Option<Pin<Box<AllocatorType>>>> = SpinLocked::new(None);
21
22/// This trait abstracts over different page frame allocator implementations.
23trait Allocator<const N: usize> {
24    /// Returns an initializer function that can be used to create an instance of the allocator.
25    /// The initializer function takes a physical address and the amount of pages needed.
26    ///
27    /// Safety:
28    ///
29    /// - The returned function must only be called with a useable and valid physical address.
30    fn initializer() -> unsafe fn(PhysAddr, usize) -> Result<Pin<Box<Self>>>;
31
32    fn alloc(&mut self, page_count: usize) -> Option<PhysAddr>;
33    #[allow(dead_code)]
34    fn free(&mut self, addr: PhysAddr, page_count: usize);
35}
36
37pub fn init_pfa(addr: PhysAddr) -> Result<()> {
38    let mut pfa = PFA.lock();
39    if pfa.is_some() {
40        return Err(kerr!(InvalidArgument));
41    }
42
43    let initializer = AllocatorType::initializer();
44    *pfa = Some(unsafe { initializer(addr, PAGE_CNT)? });
45
46    Ok(())
47}
48
49pub fn alloc_page(page_count: usize) -> Option<PhysAddr> {
50    let mut pfa = PFA.lock();
51    pfa.as_mut()?.alloc(page_count)
52}
53
54#[allow(dead_code)]
55pub fn free_page(addr: PhysAddr, page_count: usize) {
56    let mut pfa = PFA.lock();
57    if let Some(pfa) = pfa.as_mut() {
58        pfa.free(addr, page_count);
59    }
60}