frame-alloc 0.1.0

A no_std, dependency-free, const-constructible physical frame allocator for kernels
Documentation
use core::ptr::NonNull;

/// Strategy for obtaining and relinquishing compiler provenance on physical
/// frame pointers.
///
/// Implement this trait to tell the allocator how to manage provenance
/// when frames enter or leave its internal free structure.
///
/// Two stories satisfy this trait, and an implementation tells one of them:
///
/// * **Create an allocation.** `create` tells the compiler an allocation begins
///   at that address, yielding fresh provenance; `destroy` tells it the
///   allocation ends. Both must be opaque to the compiler - in practice an empty
///   `asm!` block that launders the pointer, and *without* `options(nomem)`,
///   because allocating and deallocating are memory effects. This is the story a
///   kernel tells over its direct map, and the only one available when the memory
///   is accessed atomically, since there are no volatile atomic accesses.
/// * **Recover exposed provenance.** The memory is already one live allocation
///   whose provenance was exposed; `create` recovers it with
///   [`with_exposed_provenance_mut`](core::ptr::with_exposed_provenance_mut), and
///   `destroy` reads the address back out. This fits a pool that is really a host
///   allocation, as in this crate's tests.
///
/// # Safety
///
/// * `create` must return a pointer whose provenance covers the entire
///   contiguous mapping starting at `phys` - not merely the first frame. A
///   caller may access `[phys, phys + len)` through it for any `len` that stays
///   within one physically-contiguous, exclusively-owned run (e.g. a
///   multi-frame metadata bitmap carved from one usable range).
/// * `destroy` must be called exactly once per pointer returned by `create`,
///   after which the pointer must not be used.
pub unsafe trait Provenance {
    /// Obtain a provenance-carrying pointer for a bare physical address before
    /// the allocator writes into the frame.
    ///
    /// The correct implementation for a kernel depends on how physical memory
    /// is mapped:
    ///
    /// * Convert `phys` to a virtual address.
    /// * Establish compiler provenance for it, by whichever of the two stories
    ///   above this implementation tells.
    ///
    /// # Safety
    ///
    /// `phys` must be a physical address whose memory is exclusively owned and
    /// accessible through the virtual address this function returns. The returned
    /// pointer carries provenance over the whole contiguous run starting at
    /// `phys`, so a caller may read/write any prefix of that run through it.
    ///
    /// Provenance cannot simply be asserted onto an integer. Recovering exposed
    /// provenance requires that whatever established the mapping exposed it;
    /// creating an allocation requires that the creation be opaque to the
    /// compiler. A bare `phys as *mut u8` does neither and is unsound.
    unsafe fn create(phys: usize) -> NonNull<u8>;

    /// Relinquish a frame pointer and recover the raw physical address when
    /// ownership is transferred back to the caller.
    ///
    /// Under the create-an-allocation story this is a real event, not
    /// bookkeeping: the frame is about to reach a caller who will establish their
    /// own allocation over it, and two live allocations covering the same memory
    /// would entitle the compiler to assume they do not alias. Ending the first
    /// one here is what rules that out, so the body must be opaque to the
    /// compiler in the same way `create` is.
    ///
    /// Under the recover-exposed-provenance story nothing ends - `create` never
    /// began a new allocation - and reading the address back out is a complete
    /// implementation.
    ///
    /// The contract below is the intersection of the two, which is why it binds
    /// more tightly than the second story alone needs.
    ///
    /// # Safety
    ///
    /// `ptr` must have been returned by [`Self::create`] and must not be used
    /// again after this call. Calling [`create`](Self::create) again for the same
    /// physical address is permitted and yields a fresh pointer.
    unsafe fn destroy<T>(ptr: NonNull<T>) -> usize;
}