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}