pub unsafe trait RegionInit {
// Required methods
unsafe fn try_init(
&self,
phys_base: usize,
span_len: usize,
usable: &[PhysRange],
) -> Result<(), InitError>;
unsafe fn add_usable(&self, base: usize, len: usize);
// Provided methods
unsafe fn init(
&self,
phys_base: usize,
span_len: usize,
usable: &[PhysRange],
) { ... }
unsafe fn try_init_region(
&self,
phys_base: usize,
len: usize,
) -> Result<(), InitError> { ... }
unsafe fn init_region(&self, phys_base: usize, len: usize) { ... }
}Expand description
Memory-map-aware initialisation interface for physical frame allocators.
try_init configures the allocator’s metadata over the
whole span and frees only the usable ranges; holes between them stay
reserved (never handed out).
§Contract guarantees
- On
Err, the allocator is untouched - it remains in the valid empty state it had before the call, and a corrected retry is permitted. - At most one successful call. A returned
Ok(())consumes the one-time initialisation; a returnedErr(_)does not, so a caller may retry with corrected arguments after any failure.
§Safety
These preconditions are unverifiable from the arguments and so remain the
caller’s responsibility (violating any of them is undefined behaviour, not an
InitError):
- Backends reach the managed memory through a
Provenancestrategy of their own, obtaining pointers for the physical addresses they are given; the caller supplies no mapping pointer. Each backend’sProvenance# Safetycontract states what it requires of that mapping. - Each
usablerange’s memory must be exclusively owned and not aliased while registered. - Must be called single-threaded, and the allocator must be published to other threads with a happens-before edge (thread spawn, mutex, or a Release store / Acquire load of a ready flag) before any concurrent use.
§Errors
The checkable preconditions are reported rather than assumed. See
InitError for the full list; in summary try_init returns:
InitError::AlreadyInitializedif a previous call already succeeded;InitError::Misalignedifphys_baseis not base-frame aligned (it need not itself be usable RAM);InitError::InvalidSpanifspan_lenis zero, not a base-frame multiple, or overflows the address space;InitError::InvalidUsableif anyusablerange is empty, misaligned, out of order, overlapping, or escapes the span;InitError::MetadataWontFitif no usable range can host the allocator’s in-pool metadata.
An empty usable slice is permitted by this interface, but some
implementations may reject it with InitError::MetadataWontFit: an allocator
that keeps its metadata inside the managed pool needs enough usable RAM to host
that metadata.
Required Methods§
Sourceunsafe fn try_init(
&self,
phys_base: usize,
span_len: usize,
usable: &[PhysRange],
) -> Result<(), InitError>
unsafe fn try_init( &self, phys_base: usize, span_len: usize, usable: &[PhysRange], ) -> Result<(), InitError>
Configure metadata over [phys_base, phys_base + span_len) and mark only
the usable ranges free. Holes stay reserved.
On success the one-time initialisation is consumed; on failure the
allocator is untouched and the call may be retried. See the trait-level
documentation for the full contract, the # Errors conditions, and the
# Safety preconditions.
§Errors
See the trait-level # Errors documentation.
§Safety
See the trait-level safety documentation.
Sourceunsafe fn add_usable(&self, base: usize, len: usize)
unsafe fn add_usable(&self, base: usize, len: usize)
Transition a reserved (never-freed) in-span range to free. Repeatable
after try_init. base/len must satisfy the same
per-range constraints as a usable entry.
§Safety
try_init must have succeeded first. [base, base + len) must be
base-frame aligned, lie within the span, be currently reserved (not already
free), exclusively owned, and not aliased while registered.
Provided Methods§
Sourceunsafe fn init(&self, phys_base: usize, span_len: usize, usable: &[PhysRange])
unsafe fn init(&self, phys_base: usize, span_len: usize, usable: &[PhysRange])
Examples found in repository?
91fn main() {
92 // A boot memory map with holes:
93 //
94 // The backing pool spans the whole window; we then declare only the *usable*
95 // sub-ranges. Two holes stay reserved and are never handed out:
96 //
97 // [ 0 .. 100) usable <- the buddy carves its in-pool bitmap from here
98 // [100 .. 104) RESERVED (kernel image)
99 // [104 .. 200) usable
100 // [200 .. 205) RESERVED (MMIO window)
101 // [205 .. 256) usable
102 let pool = Region::new(SPAN_FRAMES * BASE.bytes(), MAX_BLOCK);
103 let phys_base = pool.addr(); // the "physical" origin
104
105 let frame = BASE.bytes();
106 let range = |lo: usize, hi: usize| PhysRange {
107 base: phys_base + lo * frame,
108 len: (hi - lo) * frame,
109 };
110 let usable = [range(0, 100), range(104, 200), range(205, 256)];
111
112 // SAFETY: single-threaded, called once before any allocation. `phys_base` is
113 // MAX_BLOCK-aligned (Region honours the requested alignment); the bitmap host
114 // range is exclusively owned and reachable through `IdentityProv::create`; the
115 // usable ranges are sorted, non-overlapping, base-frame-aligned, and within
116 // the span.
117 unsafe { PHYS.init(phys_base, SPAN_FRAMES * frame, &usable) };
118
119 println!("Initialised SummaryBuddy over a 1 MiB span with two reserved holes.");
120 print_stats("after init", &PHYS);
121
122 // A few allocate / deallocate cycles:
123 //
124 // One single base frame, then a 4-frame (order-2) contiguous block. Every
125 // address is physical and aligned to the request size.
126 let single = PHYS
127 .allocate_physical(BASE, n(1))
128 .expect("single-frame alloc");
129 let block = PHYS
130 .allocate_physical(BASE, n(4))
131 .expect("4-frame contiguous alloc");
132 println!("\nallocate_physical(1 frame) -> {single:#x}");
133 println!("allocate_physical(4 frames) -> {block:#x}");
134 print_stats("with 5 frames out", &PHYS);
135
136 // SAFETY: each address came from `allocate_physical` with the same page size
137 // and count and is not used afterwards.
138 unsafe {
139 PHYS.deallocate_physical(BASE, n(1), single);
140 PHYS.deallocate_physical(BASE, n(4), block);
141 }
142 println!("\nfreed both — buddies merge back.");
143 print_stats("after free", &PHYS);
144
145 // Composition: a per-CPU magazine + shared depot over a fresh SummaryBuddy:
146 compose_with_depot();
147}Sourceunsafe fn init_region(&self, phys_base: usize, len: usize)
unsafe fn init_region(&self, phys_base: usize, len: usize)
As try_init_region but panic on error.
§Safety
See the trait-level safety documentation; the whole region is usable.
§Panics
Panics if initialisation returns an InitError.
Examples found in repository?
150fn compose_with_depot() {
151 /// Uniprocessor selector: every CPU maps to slot 0. A real kernel returns an
152 /// APIC id / `TPIDR_EL1` here.
153 struct OneCpu;
154 impl CpuId for OneCpu {
155 fn current_cpu() -> usize {
156 0
157 }
158 }
159 const SLOTS: usize = 8; // magazines (>= CPUs you want disjoint)
160
161 // Same const-new composability: the whole stack is one `static`-able value.
162 let mag: DepotAllocator<SummaryBuddyAllocator<ORDERS, IdentityProv>, OneCpu, SLOTS> =
163 DepotAllocator::new(BASE, SummaryBuddyAllocator::new(BASE));
164
165 let pool = Region::new(SPAN_FRAMES * BASE.bytes(), MAX_BLOCK);
166 // SAFETY: as above; here the whole region is usable, so the single-range
167 // convenience applies.
168 unsafe { mag.init_region(pool.addr(), SPAN_FRAMES * BASE.bytes()) };
169
170 println!("\n── DepotAllocator<SummaryBuddyAllocator> ──");
171 let a = mag.allocate_physical(BASE, n(1)).expect("mag alloc");
172 // SAFETY: `a` came from this allocator; freed once, then not reused by us.
173 unsafe { mag.deallocate_physical(BASE, n(1), a) };
174 let b = mag.allocate_physical(BASE, n(1)).expect("mag re-alloc");
175 println!("alloc {a:#x} -> free -> alloc {b:#x}");
176 assert_eq!(a, b, "the magazine should return the just-freed frame");
177 println!("re-alloc returned the cached frame (no backend round-trip).");
178 // SAFETY: final free of a live frame.
179 unsafe { mag.deallocate_physical(BASE, n(1), b) };
180}Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".