frame-alloc 0.1.0

A no_std, dependency-free, const-constructible physical frame allocator for kernels
Documentation
//! Shared helpers for the external (black-box) integration test suite.
//!
//! These tests link `frame_alloc` as an ordinary downstream consumer would, so
//! they exercise only the public API. The fake "physical" memory is a heap
//! allocation whose provenance is exposed and handed back to the allocator.

#![allow(dead_code)]

use core::num::NonZeroUsize;
use core::ptr::{self, NonNull};
use frame_alloc::{PageSize, Provenance};
use std::alloc::{Layout, alloc, dealloc};

pub const PS_64: PageSize = PageSize::from_log2(6);
pub const PS_256: PageSize = PageSize::from_log2(8);

pub const N1: NonZeroUsize = NonZeroUsize::MIN;

pub fn n(v: usize) -> NonZeroUsize {
    NonZeroUsize::new(v).unwrap()
}

/// RAII wrapper for a heap-allocated region used as a fake physical memory pool.
/// Frees the region on drop.
pub struct OwnedRegion {
    ptr: NonNull<u8>,
    layout: Layout,
}

impl OwnedRegion {
    pub fn new(size: usize, align: usize) -> Self {
        let layout = Layout::from_size_align(size, align).unwrap();
        let ptr = NonNull::new(unsafe { alloc(layout) }).expect("region allocation failed");
        OwnedRegion { ptr, layout }
    }

    /// Physical address for identity-mapped provenance (`TestProvenance`).
    pub fn addr(&self) -> usize {
        self.ptr.as_ptr().expose_provenance()
    }

    /// Physical address for HHDM-offset provenance (`HhdmProvenance`).
    pub fn phys_addr(&self) -> usize {
        self.addr() - HHDM_OFFSET
    }
}

impl Drop for OwnedRegion {
    fn drop(&mut self) {
        unsafe { dealloc(self.ptr.as_ptr(), self.layout) }
    }
}

pub struct TestProvenance;

// with_exposed_provenance_mut is used here because the "physical" memory is
// actually a Rust heap allocation (OwnedRegion) whose provenance was exposed
// via expose_provenance() in OwnedRegion::addr().
unsafe impl Provenance for TestProvenance {
    unsafe fn create(phys: usize) -> NonNull<u8> {
        unsafe { NonNull::new_unchecked(ptr::with_exposed_provenance_mut(phys)) }
    }

    unsafe fn destroy<T>(ptr: NonNull<T>) -> usize {
        ptr.addr().get()
    }
}

/// Simulated higher-half direct map offset. (Must be a multiple of the largest
/// test alignment.)
pub const HHDM_OFFSET: usize = 0x1000;

/// Provenance implementation that simulates a higher-half direct map.
///
/// The allocators are told that the "physical" address is `virt - HHDM_OFFSET`.
/// `create` maps physical → virtual by adding `HHDM_OFFSET`; `destroy` strips it
/// back.
pub struct HhdmProvenance;

unsafe impl Provenance for HhdmProvenance {
    unsafe fn create(phys: usize) -> NonNull<u8> {
        unsafe { NonNull::new_unchecked(ptr::with_exposed_provenance_mut(phys + HHDM_OFFSET)) }
    }

    unsafe fn destroy<T>(ptr: NonNull<T>) -> usize {
        ptr.addr().get() - HHDM_OFFSET
    }
}

#[allow(unused_imports)]
pub use regioned::Regioned1;

/// Single-region `RegionedAllocator` adapter used to drive the wrapper through
/// the black-box conformance suite.
mod regioned {
    use core::num::NonZeroUsize;
    #[cfg(feature = "stats")]
    use frame_alloc::AllocatorStats;
    use frame_alloc::{
        AllocError, InitError, PageSize, PhysRange, PhysicalAllocator, RegionInit,
        RegionedAllocator,
    };

    pub struct Regioned1<A>(RegionedAllocator<1, A>);

    impl<A> Regioned1<A> {
        pub fn new(base: PageSize, inner: A) -> Self {
            Regioned1(RegionedAllocator::new(base, [inner]))
        }
    }

    unsafe impl<A: RegionInit> RegionInit for Regioned1<A> {
        unsafe fn try_init(
            &self,
            phys_base: usize,
            span_len: usize,
            usable: &[PhysRange],
        ) -> Result<(), InitError> {
            // SAFETY: forwarded verbatim under the caller's `RegionInit` guarantees;
            // the lone region owns the whole span.
            unsafe { self.0.try_init_at(0, phys_base, span_len, usable) }
        }

        unsafe fn add_usable(&self, base: usize, len: usize) {
            // SAFETY: `[base, base + len)` lies in the single region's span; the
            // wrapper re-checks ownership and forwards the backend contract.
            unsafe { self.0.add_usable(base, len) };
        }
    }

    unsafe impl<A: PhysicalAllocator> PhysicalAllocator for Regioned1<A> {
        fn allocate_physical(
            &self,
            ps: PageSize,
            count: NonZeroUsize,
        ) -> Result<usize, AllocError> {
            self.0.allocate_physical(ps, count)
        }

        unsafe fn deallocate_physical(&self, ps: PageSize, count: NonZeroUsize, phys: usize) {
            // SAFETY: `phys` came from this wrapper; the caller upholds the per-frame
            // contract.
            unsafe { self.0.deallocate_physical(ps, count, phys) };
        }
    }

    #[cfg(feature = "stats")]
    impl<A: AllocatorStats> AllocatorStats for Regioned1<A> {
        fn total_bytes(&self) -> usize {
            self.0.total_bytes()
        }

        fn free_bytes(&self) -> usize {
            self.0.free_bytes()
        }

        fn largest_free_bytes(&self) -> usize {
            self.0.largest_free_bytes()
        }
    }
}