Skip to main content

frame_alloc/strategies/
provenance.rs

1use core::ptr::NonNull;
2
3/// Strategy for obtaining and relinquishing compiler provenance on physical
4/// frame pointers.
5///
6/// Implement this trait to tell the allocator how to manage provenance
7/// when frames enter or leave its internal free structure.
8///
9/// Two stories satisfy this trait, and an implementation tells one of them:
10///
11/// * **Create an allocation.** `create` tells the compiler an allocation begins
12///   at that address, yielding fresh provenance; `destroy` tells it the
13///   allocation ends. Both must be opaque to the compiler - in practice an empty
14///   `asm!` block that launders the pointer, and *without* `options(nomem)`,
15///   because allocating and deallocating are memory effects. This is the story a
16///   kernel tells over its direct map, and the only one available when the memory
17///   is accessed atomically, since there are no volatile atomic accesses.
18/// * **Recover exposed provenance.** The memory is already one live allocation
19///   whose provenance was exposed; `create` recovers it with
20///   [`with_exposed_provenance_mut`](core::ptr::with_exposed_provenance_mut), and
21///   `destroy` reads the address back out. This fits a pool that is really a host
22///   allocation, as in this crate's tests.
23///
24/// # Safety
25///
26/// * `create` must return a pointer whose provenance covers the entire
27///   contiguous mapping starting at `phys` - not merely the first frame. A
28///   caller may access `[phys, phys + len)` through it for any `len` that stays
29///   within one physically-contiguous, exclusively-owned run (e.g. a
30///   multi-frame metadata bitmap carved from one usable range).
31/// * `destroy` must be called exactly once per pointer returned by `create`,
32///   after which the pointer must not be used.
33pub unsafe trait Provenance {
34    /// Obtain a provenance-carrying pointer for a bare physical address before
35    /// the allocator writes into the frame.
36    ///
37    /// The correct implementation for a kernel depends on how physical memory
38    /// is mapped:
39    ///
40    /// * Convert `phys` to a virtual address.
41    /// * Establish compiler provenance for it, by whichever of the two stories
42    ///   above this implementation tells.
43    ///
44    /// # Safety
45    ///
46    /// `phys` must be a physical address whose memory is exclusively owned and
47    /// accessible through the virtual address this function returns. The returned
48    /// pointer carries provenance over the whole contiguous run starting at
49    /// `phys`, so a caller may read/write any prefix of that run through it.
50    ///
51    /// Provenance cannot simply be asserted onto an integer. Recovering exposed
52    /// provenance requires that whatever established the mapping exposed it;
53    /// creating an allocation requires that the creation be opaque to the
54    /// compiler. A bare `phys as *mut u8` does neither and is unsound.
55    unsafe fn create(phys: usize) -> NonNull<u8>;
56
57    /// Relinquish a frame pointer and recover the raw physical address when
58    /// ownership is transferred back to the caller.
59    ///
60    /// Under the create-an-allocation story this is a real event, not
61    /// bookkeeping: the frame is about to reach a caller who will establish their
62    /// own allocation over it, and two live allocations covering the same memory
63    /// would entitle the compiler to assume they do not alias. Ending the first
64    /// one here is what rules that out, so the body must be opaque to the
65    /// compiler in the same way `create` is.
66    ///
67    /// Under the recover-exposed-provenance story nothing ends - `create` never
68    /// began a new allocation - and reading the address back out is a complete
69    /// implementation.
70    ///
71    /// The contract below is the intersection of the two, which is why it binds
72    /// more tightly than the second story alone needs.
73    ///
74    /// # Safety
75    ///
76    /// `ptr` must have been returned by [`Self::create`] and must not be used
77    /// again after this call. Calling [`create`](Self::create) again for the same
78    /// physical address is permitted and yields a fresh pointer.
79    unsafe fn destroy<T>(ptr: NonNull<T>) -> usize;
80}