ostd/mm/frame/mod.rs
1// SPDX-License-Identifier: MPL-2.0
2//! Frame (physical memory page) management.
3//!
4//! A frame is an aligned, contiguous range of bytes in physical memory. The
5//! sizes of base frames and huge frames (that are mapped as "huge pages") are
6//! architecture-dependent. A frame can be mapped to virtual address spaces
7//! using the page table.
8//!
9//! Frames can be accessed through frame handles, namely, [`Frame`]. A frame
10//! handle is a reference-counted pointer to a frame. When all handles to a
11//! frame are dropped, the frame is released and can be reused. Contiguous
12//! frames are managed with [`Segment`].
13//!
14//! There are various kinds of frames. The top-level grouping of frame kinds
15//! are "typed" frames and "untyped" frames. Typed frames host Rust objects
16//! that must follow the visibility, lifetime and borrow rules of Rust, thus
17//! not being able to be directly manipulated. Untyped frames are raw memory
18//! that can be manipulated directly. So only untyped frames can be
19//! - safely shared to external entities such as device drivers or user-space
20//! applications.
21//! - or directly manipulated with readers and writers that neglect Rust's
22//! "alias XOR mutability" rule.
23//!
24//! The kind of a frame is determined by the type of its metadata. Untyped
25//! frames have its metadata type that implements the [`AnyUFrameMeta`]
26//! trait, while typed frames don't.
27//!
28//! Frames can have dedicated metadata, which is implemented in the [`meta`]
29//! module. The reference count and usage of a frame are stored in the metadata
30//! as well, leaving the handle only a pointer to the metadata slot. Users
31//! can create custom metadata types by implementing the [`AnyFrameMeta`] trait.
32//pub mod allocator;
33pub mod allocator;
34pub mod linked_list;
35pub mod meta;
36pub mod segment;
37pub mod unique;
38pub mod untyped;
39
40mod frame_ref;
41
42#[cfg(ktest)]
43mod test;
44
45use vstd::atomic::PermissionU64;
46use vstd::prelude::*;
47use vstd::simple_pptr::{self, PPtr};
48
49use vstd_extra::cast_ptr;
50
51use core::{
52 marker::PhantomData,
53 sync::atomic::{AtomicUsize, Ordering},
54};
55
56//pub use allocator::GlobalFrameAllocator;
57use meta::REF_COUNT_UNUSED;
58pub use segment::Segment;
59
60// Re-export commonly used types
61use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
62pub use frame_ref::FrameRef;
63pub use linked_list::{CursorMut, Link, LinkedList};
64pub use meta::mapping::{
65 frame_to_index, frame_to_index_spec, frame_to_meta, meta_addr, meta_to_frame, META_SLOT_SIZE,
66};
67pub use meta::{has_safe_slot, AnyFrameMeta, GetFrameError, MetaSlot};
68pub use unique::UniqueFrame;
69pub use untyped::{AnyUFrameMeta, UFrame};
70
71use crate::mm::page_table::{PageTableConfig, PageTablePageMeta};
72
73use vstd_extra::cast_ptr::*;
74use vstd_extra::drop_tracking::*;
75use vstd_extra::ownership::*;
76
77use crate::mm::{
78 kspace::{LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR},
79 Paddr, PagingLevel, Vaddr, MAX_PADDR,
80};
81use crate::specs::arch::mm::{MAX_NR_PAGES, PAGE_SIZE};
82use crate::specs::mm::frame::frame_specs::*;
83use crate::specs::mm::frame::meta_owners::*;
84use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
85use crate::mm::page_table::RCClone;
86
87verus! {
88
89/// A smart pointer to a frame.
90///
91/// A frame is a contiguous range of bytes in physical memory. The [`Frame`]
92/// type is a smart pointer to a frame that is reference-counted.
93///
94/// Frames are associated with metadata. The type of the metadata `M` is
95/// determines the kind of the frame. If `M` implements [`AnyUFrameMeta`], the
96/// frame is a untyped frame. Otherwise, it is a typed frame.
97/// # Verification Design
98#[repr(transparent)]
99pub struct Frame<M: AnyFrameMeta> {
100 pub ptr: PPtr<MetaSlot>,
101 pub _marker: PhantomData<M>,
102}
103
104/// We need to keep track of when frames are forgotten with `ManuallyDrop`.
105/// We maintain a counter for each frame of how many times it has been forgotten (`raw_count`).
106/// Calling `ManuallyDrop::new` increments the counter. It is technically safe to forget a frame multiple times,
107/// and this will happen with read-only `FrameRef`s. All such references need to be dropped by the time
108/// `from_raw` is called. So, `ManuallyDrop::drop` decrements the counter when the reference is dropped,
109/// and `from_raw` may only be called when the counter is 1.
110impl<M: AnyFrameMeta> TrackDrop for Frame<M> {
111 type State = MetaRegionOwners;
112
113 open spec fn constructor_requires(self, s: Self::State) -> bool {
114 &&& s.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
115 &&& s.inv()
116 }
117
118 open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool {
119 let slot_own = s0.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))];
120 &&& s1.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))] == MetaSlotOwner {
121 raw_count: (slot_own.raw_count + 1) as usize,
122 ..slot_own
123 }
124 &&& forall|i: usize|
125 #![trigger s1.slot_owners[i]]
126 i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s1.slot_owners[i]
127 == s0.slot_owners[i]
128 &&& s1.slots =~= s0.slots
129 &&& s1.slot_owners.dom() =~= s0.slot_owners.dom()
130 }
131
132 proof fn constructor_spec(self, tracked s: &mut Self::State) {
133 let meta_addr = self.ptr.addr();
134 let index = frame_to_index(meta_to_frame(meta_addr));
135 let tracked mut slot_own = s.slot_owners.tracked_remove(index);
136 slot_own.raw_count = (slot_own.raw_count + 1) as usize;
137 s.slot_owners.tracked_insert(index, slot_own);
138 }
139
140 open spec fn drop_requires(self, s: Self::State) -> bool {
141 &&& s.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
142 &&& s.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count > 0
143 }
144
145 open spec fn drop_ensures(self, s0: Self::State, s1: Self::State) -> bool {
146 let slot_own = s0.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))];
147 &&& s1.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == (
148 slot_own.raw_count - 1) as usize
149 &&& forall|i: usize|
150 #![trigger s1.slot_owners[i]]
151 i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s1.slot_owners[i]
152 == s0.slot_owners[i]
153 &&& s1.slots =~= s0.slots
154 &&& s1.slot_owners.dom() =~= s0.slot_owners.dom()
155 }
156
157 proof fn drop_spec(self, tracked s: &mut Self::State) {
158 let index = frame_to_index(meta_to_frame(self.ptr.addr()));
159 let tracked mut slot_own = s.slot_owners.tracked_remove(index);
160 slot_own.raw_count = (slot_own.raw_count - 1) as usize;
161 s.slot_owners.tracked_insert(index, slot_own);
162 }
163}
164
165impl<M: AnyFrameMeta> Inv for Frame<M> {
166 open spec fn inv(self) -> bool {
167 &&& self.ptr.addr() % META_SLOT_SIZE == 0
168 &&& FRAME_METADATA_RANGE.start <= self.ptr.addr() < FRAME_METADATA_RANGE.start
169 + MAX_NR_PAGES * META_SLOT_SIZE
170 }
171}
172
173impl<M: AnyFrameMeta> Frame<M> {
174 pub open spec fn paddr(self) -> usize {
175 meta_to_frame(self.ptr.addr())
176 }
177
178 pub open spec fn index(self) -> usize {
179 frame_to_index(self.paddr())
180 }
181}
182
183#[verus_verify]
184impl<'a, M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
185 /// Gets a [`Frame`] with a specific usage from a raw, unused page.
186 ///
187 /// The caller should provide the initial metadata of the page.
188 ///
189 /// If the provided frame is not truly unused at the moment, it will return
190 /// an error. If wanting to acquire a frame that is already in use, use
191 /// [`Frame::from_in_use`] instead.
192 /// # Verified Properties
193 /// ## Preconditions
194 /// - **Safety Invariant**: Metaslot region invariants must hold.
195 /// - **Bookkeeping**: The slot must be available in order to get the permission.
196 /// This is stronger than it needs to be; absent permissions correspond to error cases.
197 /// ## Postconditions
198 /// - **Safety Invariant**: Metaslot region invariants hold after the call.
199 /// - **Correctness**: If successful, the function returns a pointer to the metadata slot and a permission to the slot.
200 /// - **Correctness**: If successful, the slot is initialized with the given metadata.
201 /// ## Safety
202 /// - This function returns an error if `paddr` does not correspond to a valid slot or the slot is in use.
203 #[verus_spec(r =>
204 with
205 Tracked(regions): Tracked<&mut MetaRegionOwners>
206 -> perm: Tracked<Option<PointsTo<MetaSlot, Metadata<M>>>>
207 requires
208 old(regions).inv(),
209 old(regions).slots.contains_key(frame_to_index(paddr)),
210 ensures
211 regions.inv(),
212 r matches Ok(res) ==> perm@ is Some && MetaSlot::get_from_unused_perm_spec(paddr, metadata, false, res.ptr, perm@.unwrap()),
213 r is Ok ==> MetaSlot::get_from_unused_spec(paddr, false, *old(regions), *regions),
214 !has_safe_slot(paddr) ==> r is Err,
215 )]
216 pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
217 #[verus_spec(with Tracked(regions))]
218 let from_unused = MetaSlot::get_from_unused(paddr, metadata, false);
219 if let Err(err) = from_unused {
220 proof_with!(|= Tracked(None));
221 Err(err)
222 } else {
223 let (ptr, Tracked(perm)) = from_unused.unwrap();
224 proof_with!(|= Tracked(Some(perm)));
225 Ok(Self { ptr, _marker: PhantomData })
226 }
227 }
228
229 /// Gets the metadata of this page.
230 /// # Verified Properties
231 /// ## Preconditions
232 /// - The caller must have a valid permission for the frame.
233 /// ## Postconditions
234 /// - The function returns the metadata of the frame.
235 /// ## Safety
236 /// - By requiring the caller to provide a typed permission, we ensure that the metadata is of type `M`.
237 /// While a non-verified caller cannot be trusted to obey this interface, all functions that return a `Frame<M>` also
238 /// return an appropriate permission.
239 #[verus_spec(
240 with Tracked(perm) : Tracked<&'a PointsTo<MetaSlot, Metadata<M>>>,
241 requires
242 self.ptr.addr() == perm.addr(),
243 self.ptr == perm.points_to.pptr(),
244 perm.is_init(),
245 perm.wf(&perm.inner_perms),
246 returns
247 perm.value().metadata,
248 )]
249 pub fn meta(&self) -> &'a M {
250 // SAFETY: The type is tracked by the type system.
251 #[verus_spec(with Tracked(&perm.points_to))]
252 let slot = self.slot();
253
254 #[verus_spec(with Tracked(&perm.points_to))]
255 let ptr = slot.as_meta_ptr();
256
257 &ptr.borrow(Tracked(perm)).metadata
258 }
259}
260
261#[verus_verify]
262impl<M: AnyFrameMeta> Frame<M> {
263 /// Gets a dynamically typed [`Frame`] from a raw, in-use page.
264 ///
265 /// If the provided frame is not in use at the moment, it will return an error.
266 ///
267 /// The returned frame will have an extra reference count to the frame.
268 ///
269 /// # Verified Properties
270 /// ## Preconditions
271 /// - **Safety Invariant**: Metaslot region invariants must hold.
272 /// - **Liveness**: The slot must have fewer than `REF_COUNT_MAX - 1` references or the function will panic.
273 /// ## Postconditions
274 /// - **Safety Invariant**: Metaslot region invariants hold after the call.
275 /// - **Correctness**: If successful, the function returns the frame at `paddr`.
276 /// - **Correctness**: If successful, the frame has an extra reference count to the frame.
277 /// - **Safety**: Frames other than the one at `paddr` are not affected by the call.
278 /// ## Safety
279 /// - If `paddr` is a valid frame address, it is safe to take a reference to the frame.
280 /// - If `paddr` is not a valid frame address, the function will return an error.
281 #[verus_spec(res =>
282 with Tracked(regions) : Tracked<&mut MetaRegionOwners>,
283 requires
284 old(regions).inv(),
285 old(regions).slots.contains_key(frame_to_index(paddr)),
286 !MetaSlot::get_from_in_use_panic_cond(paddr, *old(regions)),
287 ensures
288 regions.inv(),
289 res is Ok ==>
290 regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() ==
291 old(regions).slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1,
292 res matches Ok(res) ==>
293 res.ptr == old(regions).slots[frame_to_index(paddr)].pptr(),
294 !has_safe_slot(paddr) ==> res is Err,
295 forall|i: usize|
296 #![trigger regions.slot_owners[i]]
297 i != frame_to_index(paddr) ==> regions.slot_owners[i] == old(regions).slot_owners[i]
298 )]
299 pub fn from_in_use(paddr: Paddr) -> Result<Self, GetFrameError> {
300 #[verus_spec(with Tracked(regions))]
301 let from_in_use = MetaSlot::get_from_in_use(paddr);
302 Ok(Self { ptr: from_in_use?, _marker: PhantomData })
303 }
304}
305
306#[verus_verify]
307impl<'a, M: AnyFrameMeta> Frame<M> {
308 /// Gets the physical address of the start of the frame.
309 #[verus_spec(
310 with Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
311 )]
312 pub fn start_paddr(&self) -> Paddr
313 requires
314 perm.addr() == self.ptr.addr(),
315 perm.is_init(),
316 FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end,
317 perm.addr() % META_SLOT_SIZE == 0,
318 returns
319 meta_to_frame(self.ptr.addr()),
320 {
321 #[verus_spec(with Tracked(perm))]
322 let slot = self.slot();
323
324 #[verus_spec(with Tracked(perm))]
325 slot.frame_paddr()
326 }
327
328 /// Gets the map level of this page.
329 ///
330 /// This is the level of the page table entry that maps the frame,
331 /// which determines the size of the frame.
332 ///
333 /// Currently, the level is always 1, which means the frame is a regular
334 /// page frame.
335 pub const fn map_level(&self) -> PagingLevel {
336 1
337 }
338
339 /// Gets the size of this page in bytes.
340 pub const fn size(&self) -> usize {
341 PAGE_SIZE
342 }
343
344 /* /// Gets the dynamically-typed metadata of this frame.
345 ///
346 /// If the type is known at compile time, use [`Frame::meta`] instead.
347 pub fn dyn_meta(&self) -> FrameMeta {
348 // SAFETY: The metadata is initialized and valid.
349 unsafe { &*self.slot().dyn_meta_ptr() }
350 }*/
351 /// Gets the reference count of the frame.
352 ///
353 /// It returns the number of all references to the frame, including all the
354 /// existing frame handles ([`Frame`], [`Frame<dyn AnyFrameMeta>`]), and all
355 /// the mappings in the page table that points to the frame.
356 ///
357 /// # Verified Properties
358 /// ## Preconditions
359 /// - **Safety Invariant**: Metaslot region invariants must hold.
360 /// - **Bookkeeping**: The caller must have a valid and well-typed permission for the frame.
361 /// ## Postconditions
362 /// - **Correctness**: The function returns the reference count of the frame.
363 /// ## Safety
364 /// - The function is safe to call, but using it requires extra care. The
365 /// reference count can be changed by other threads at any time including
366 /// potentially between calling this method and acting on the result.
367 #[verus_spec(
368 with Tracked(slot_own): Tracked<&mut MetaSlotOwner>,
369 Tracked(perm) : Tracked<&PointsTo<MetaSlot, Metadata<M>>>
370 )]
371 pub fn reference_count(&self) -> u64
372 requires
373 perm.addr() == self.ptr.addr(),
374 perm.points_to.pptr() == self.ptr,
375 perm.is_init(),
376 perm.wf(&perm.inner_perms),
377 perm.inner_perms.ref_count.id() == perm.points_to.value().ref_count.id(),
378 returns
379 perm.value().ref_count,
380 {
381 #[verus_spec(with Tracked(&perm.points_to))]
382 let slot = self.slot();
383 slot.ref_count.load(Tracked(&perm.inner_perms.ref_count))
384 }
385
386 /// Borrows a reference from the given frame.
387 /// # Verified Properties
388 /// ## Preconditions
389 /// - **Safety Invariant**: Metaslot region invariants must hold.
390 /// - **Bookkeeping**: The caller must have a valid and well-typed permission for the frame.
391 /// ## Postconditions
392 /// - **Safety Invariant**: Metaslot region invariants hold after the call.
393 /// - **Correctness**: The function returns a reference to the frame.
394 /// - **Correctness**: The system context is unchanged.
395 #[verus_spec(res =>
396 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
397 Tracked(perm): Tracked<&MetaPerm<M>>,
398 requires
399 old(regions).inv(),
400 old(regions).slot_owners[self.index()].raw_count <= 1,
401 old(regions).slot_owners[self.index()].self_addr == self.ptr.addr(),
402 perm.points_to.pptr() == self.ptr,
403 perm.points_to.value().wf(old(regions).slot_owners[self.index()]),
404 perm.is_init(),
405 self.inv(),
406 ensures
407 regions.inv(),
408 res.inner@.ptr.addr() == self.ptr.addr(),
409 // raw_count is always 1 after borrow
410 regions.slot_owners[self.index()].raw_count == 1,
411 // All other fields of this slot are preserved
412 regions.slot_owners[self.index()].inner_perms
413 == old(regions).slot_owners[self.index()].inner_perms,
414 regions.slot_owners[self.index()].self_addr
415 == old(regions).slot_owners[self.index()].self_addr,
416 regions.slot_owners[self.index()].usage
417 == old(regions).slot_owners[self.index()].usage,
418 regions.slot_owners[self.index()].path_if_in_pt
419 == old(regions).slot_owners[self.index()].path_if_in_pt,
420 // Other slots are unchanged
421 forall |i: usize|
422 #![trigger regions.slot_owners[i]]
423 i != self.index() ==> regions.slot_owners[i]
424 == old(regions).slot_owners[i],
425 regions.slot_owners.dom() =~= old(regions).slot_owners.dom(),
426 )]
427 pub fn borrow(&self) -> FrameRef<'a, M> {
428 assert(regions.slot_owners.contains_key(self.index()));
429 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
430
431 // SAFETY: Both the lifetime and the type matches `self`.
432 #[verus_spec(with Tracked(&perm.points_to))]
433 let paddr = self.start_paddr();
434
435 #[verus_spec(with Tracked(regions), Tracked(perm))]
436 FrameRef::borrow_paddr(paddr)
437 }
438
439 /// Forgets the handle to the frame.
440 ///
441 /// This will result in the frame being leaked without calling the custom dropper.
442 ///
443 /// A physical address to the frame is returned in case the frame needs to be
444 /// restored using [`Frame::from_raw`] later. This is useful when some architectural
445 /// data structures need to hold the frame handle such as the page table.
446 ///
447 /// # Verified Properties
448 /// ## Preconditions
449 /// - **Safety Invariant**: Metaslot region invariants must hold.
450 /// - **Safety**: The frame must be in use (not unused).
451 /// ## Postconditions
452 /// - **Safety Invariant**: Metaslot region invariants hold after the call.
453 /// - **Correctness**: The function returns the physical address of the frame.
454 /// - **Correctness**: The frame's raw count is incremented.
455 /// - **Safety**: Frames other than this one are not affected by the call.
456 /// ## Safety
457 /// - We require the slot to be in use to ensure that a fresh frame handle will not be created until the raw frame is restored.
458 /// - The owner's raw count is incremented so that we can enforce the safety requirement on `Frame::from_raw`.
459 #[verus_spec(r =>
460 with
461 Tracked(regions): Tracked<&mut MetaRegionOwners>,
462 -> frame_perm: Tracked<MetaPerm<M>>,
463 requires
464 old(regions).inv(),
465 old(regions).slots.contains_key(self.index()),
466 self.inv(),
467 old(regions).slot_owners[self.index()].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
468 ensures
469 regions.inv(),
470 r == self.paddr(),
471 frame_perm@.points_to == old(regions).slots[self.index()],
472 regions.slot_owners[self.index()].raw_count
473 == (old(regions).slot_owners[self.index()].raw_count + 1) as usize,
474 self.into_raw_post_noninterference(*old(regions), *regions),
475 )]
476 pub(in crate::mm) fn into_raw(self) -> Paddr {
477 broadcast use crate::mm::frame::meta::mapping::group_page_meta;
478
479 let tracked perm = regions.slots.tracked_borrow(self.index());
480
481 assert(perm.addr() == self.ptr.addr()) by {
482 assert(frame_to_meta(meta_to_frame(self.ptr.addr())) == self.ptr.addr());
483 };
484
485 #[verus_spec(with Tracked(perm))]
486 let paddr = self.start_paddr();
487
488 let ghost index = self.index();
489
490 assert(self.constructor_requires(*regions));
491 let _ = ManuallyDrop::new(self, Tracked(regions));
492
493 assert(regions.slots.contains_key(index));
494 let tracked meta_perm = regions.copy_perm::<M>(index);
495
496 proof_with!(|= Tracked(meta_perm));
497 paddr
498 }
499
500 /// Restores a forgotten [`Frame`] from a physical address.
501 ///
502 /// # Safety
503 ///
504 /// The caller should only restore a `Frame` that was previously forgotten using
505 /// [`Frame::into_raw`].
506 ///
507 /// And the restoring operation should only be done once for a forgotten
508 /// [`Frame`]. Otherwise double-free will happen.
509 ///
510 /// Also, the caller ensures that the usage of the frame is correct. There's
511 /// no checking of the usage in this function.
512 ///
513 /// # Verified Properties
514 /// ## Preconditions
515 /// - **Safety Invariant**: Metaslot region invariants must hold.
516 /// - **Safety**: The caller must have a valid and well-typed permission for the frame.
517 /// - **Safety**: There must be at least one raw frame at `paddr`.
518 /// ## Postconditions
519 /// - **Safety Invariant**: Metaslot region invariants hold after the call.
520 /// - **Correctness**: The function returns the frame at `paddr`.
521 /// - **Correctness**: The frame's raw count is decremented.
522 /// - **Safety**: Frames other than this one are not affected by the call.
523 /// - **Safety**: The count of raw frames is restored to 0.
524 /// ## Safety
525 /// - When `into_raw` was called, the frame was marked to be ignored by the garbage collector.
526 /// Now we construct a new frame at the same address, which will be managed by the garbage collector again.
527 /// We ensure that we only do this once by setting the raw count to 0. We will only call this function again
528 /// if we have since forgotten the frame again.
529 #[verus_spec(r =>
530 with
531 Tracked(regions): Tracked<&mut MetaRegionOwners>,
532 Tracked(perm): Tracked<&MetaPerm<M>>,
533 -> debt: Tracked<BorrowDebt>,
534 requires
535 Self::from_raw_requires_safety(*old(regions), paddr),
536 old(regions).slot_owners[frame_to_index(paddr)].raw_count <= 1,
537 perm.points_to.is_init(),
538 perm.points_to.addr() == frame_to_meta(paddr),
539 perm.points_to.value().wf(old(regions).slot_owners[frame_to_index(paddr)]),
540 ensures
541 Self::from_raw_ensures(*old(regions), *regions, paddr, r),
542 regions.slots == old(regions).slots.insert(frame_to_index(paddr), perm.points_to),
543 debt@.frame_index == frame_to_index(paddr),
544 debt@.raw_count_at_issue == old(regions).slot_owners[frame_to_index(paddr)].raw_count,
545 )]
546 pub(in crate::mm) fn from_raw(paddr: Paddr) -> Self {
547 let vaddr = frame_to_meta(paddr);
548 let ptr = PPtr::from_addr(vaddr);
549
550 let ghost idx = frame_to_index(paddr);
551 let ghost old_raw_count = regions.slot_owners[idx].raw_count;
552
553 proof {
554 let index = frame_to_index(paddr);
555 regions.sync_perm::<M>(index, perm);
556
557 let tracked mut slot_own = regions.slot_owners.tracked_remove(index);
558 slot_own.raw_count = 0usize;
559 regions.slot_owners.tracked_insert(index, slot_own);
560 }
561
562 proof_with!(|= Tracked(BorrowDebt { frame_index: idx, raw_count_at_issue: old_raw_count }));
563 Self { ptr, _marker: PhantomData }
564 }
565
566 /// Gets the metadata slot of the frame.
567 ///
568 /// # Verified Properties
569 /// ## Preconditions
570 /// - **Safety**: The caller must have a valid permission for the frame.
571 /// ## Postconditions
572 /// - **Correctness**: The function returns a reference to the metadata slot of the frame.
573 /// ## Safety
574 /// - There is no way to mutably borrow the metadata slot, so taking an immutable reference is safe.
575 /// (The fields of the slot can be mutably borrowed, but not the slot itself.)
576 #[verus_spec(
577 with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
578 )]
579 pub fn slot(&self) -> (slot: &'a MetaSlot)
580 requires
581 slot_perm.pptr() == self.ptr,
582 slot_perm.is_init(),
583 returns
584 slot_perm.value(),
585 {
586 // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
587 // mutably borrowed, so taking an immutable reference to it is safe.
588 self.ptr.borrow(Tracked(slot_perm))
589 }
590}
591
592/// Increases the reference count of the frame by one.
593///
594/// # Verified Properties
595/// ## Preconditions
596/// - **Safety Invariant**: Metaslot region invariants must hold.
597/// - **Safety**: The physical address must represent a valid frame.
598/// ## Postconditions
599/// - **Safety Invariant**: Metaslot region invariants hold after the call.
600/// - **Correctness**: The reference count of the frame is increased by one.
601/// - **Safety**: Frames other than this one are not affected by the call.
602/// ## Safety
603/// We enforce the safety requirements that `paddr` represents a valid frame and the caller has already held a reference to the it.
604/// It is safe to require these as preconditions because the function is internal, so the caller must obey the preconditions.
605#[verus_spec(
606 with Tracked(regions): Tracked<&mut MetaRegionOwners>
607)]
608pub(in crate::mm) fn inc_frame_ref_count(paddr: Paddr)
609 requires
610 old(regions).inv(),
611 old(regions).slots.contains_key(frame_to_index(paddr)),
612 has_safe_slot(paddr),
613 !MetaSlot::inc_ref_count_panic_cond(
614 old(regions).slot_owners[frame_to_index(paddr)].inner_perms.ref_count,
615 ),
616 ensures
617 regions.inv(),
618 regions.slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() == old(
619 regions,
620 ).slot_owners[frame_to_index(paddr)].inner_perms.ref_count.value() + 1,
621 regions.slots =~= old(regions).slots,
622 forall|i: usize|
623 i != frame_to_index(paddr) ==> (#[trigger] regions.slot_owners[i] == old(
624 regions,
625 ).slot_owners[i]),
626 regions.slot_owners.dom() =~= old(regions).slot_owners.dom(),
627{
628 let tracked mut slot_own = regions.slot_owners.tracked_remove(frame_to_index(paddr));
629 let tracked perm = regions.slots.tracked_borrow(frame_to_index(paddr));
630 let tracked mut inner_perms = slot_own.take_inner_perms();
631
632 let vaddr: Vaddr = frame_to_meta(paddr);
633 // SAFETY: `vaddr` points to a valid `MetaSlot` that will never be mutably borrowed, so taking
634 // an immutable reference to it is always safe.
635 let slot = PPtr::<MetaSlot>::from_addr(vaddr);
636
637 #[verus_spec(with Tracked(&mut inner_perms.ref_count))]
638 slot.borrow(Tracked(perm)).inc_ref_count();
639
640 proof {
641 admit();
642 slot_own.sync_inner(&inner_perms);
643 regions.slot_owners.tracked_insert(frame_to_index(paddr), slot_own);
644 }
645}
646
647/// A dynamically-typed frame is represented by a frame of the underlying metadata type,
648/// which can be cast from any other type.
649pub type DynFrame = Frame<MetaSlotStorage>;
650
651#[verus_verify]
652impl<M: AnyFrameMeta + ?Sized> RCClone for Frame<M> {
653
654 open spec fn clone_requires(self, slot_perm: simple_pptr::PointsTo<MetaSlot>, rc_perm: PermissionU64) -> bool {
655 &&& self.ptr.addr() == slot_perm.addr()
656 &&& slot_perm.is_init()
657 &&& !MetaSlot::inc_ref_count_panic_cond(rc_perm)
658 }
659
660 fn clone(&self, Tracked(slot_perm): Tracked<&simple_pptr::PointsTo<MetaSlot>>, Tracked(rc_perm): Tracked<&mut PermissionU64>) -> Self
661 {
662 // SAFETY: We have already held a reference to the frame.
663 #[verus_spec(with Tracked(slot_perm))]
664 let slot = self.slot();
665
666 #[verus_spec(with Tracked(rc_perm))]
667 slot.inc_ref_count();
668
669 Self {
670 ptr: PPtr::<MetaSlot>::from_addr(self.ptr.0),
671 _marker: PhantomData,
672 }
673 }
674}
675/*
676impl<M: AnyFrameMeta + ?Sized> Drop for Frame<M> {
677 fn drop(&mut self) {
678 let last_ref_cnt = self.slot().ref_count.fetch_sub(1, Ordering::Release);
679 debug_assert!(last_ref_cnt != 0 && last_ref_cnt != REF_COUNT_UNUSED);
680
681 if last_ref_cnt == 1 {
682 // A fence is needed here with the same reasons stated in the implementation of
683 // `Arc::drop`: <https://doc.rust-lang.org/std/sync/struct.Arc.html#method.drop>.
684 core::sync::atomic::fence(Ordering::Acquire);
685
686 // SAFETY: this is the last reference and is about to be dropped.
687 unsafe { self.slot().drop_last_in_place() };
688
689 allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
690 }
691 }
692}
693*/
694/*
695impl<M: AnyFrameMeta> TryFrom<Frame<dyn AnyFrameMeta>> for Frame<M> {
696 type Error = Frame<dyn AnyFrameMeta>;
697
698 /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into the statically-typed [`Frame`].
699 ///
700 /// If the usage of the frame is not the same as the expected usage, it will
701 /// return the dynamic frame itself as is.
702 fn try_from(dyn_frame: Frame<dyn AnyFrameMeta>) -> Result<Self, Self::Error> {
703 if (dyn_frame.dyn_meta() as &dyn core::any::Any).is::<M>() {
704 // SAFETY: The metadata is coerceable and the struct is transmutable.
705 Ok(unsafe { core::mem::transmute::<Frame<dyn AnyFrameMeta>, Frame<M>>(dyn_frame) })
706 } else {
707 Err(dyn_frame)
708 }
709 }
710}*/
711/*impl<M: AnyFrameMeta> From<Frame<M>> for Frame<dyn AnyFrameMeta> {
712 fn from(frame: Frame<M>) -> Self {
713 // SAFETY: The metadata is coerceable and the struct is transmutable.
714 unsafe { core::mem::transmute(frame) }
715 }
716}*/
717
718/*impl From<UFrame> for Frame<FrameMeta> {
719 fn from(frame: UFrame) -> Self {
720 // SAFETY: The metadata is coerceable and the struct is transmutable.
721 unsafe { core::mem::transmute(frame) }
722 }
723}*/
724/*impl TryFrom<Frame<FrameMeta>> for UFrame {
725 type Error = Frame<FrameMeta>;
726
727 /// Tries converting a [`Frame<dyn AnyFrameMeta>`] into [`UFrame`].
728 ///
729 /// If the usage of the frame is not the same as the expected usage, it will
730 /// return the dynamic frame itself as is.
731 fn try_from(dyn_frame: Frame<FrameMeta>) -> Result<Self, Self::Error> {
732 if dyn_frame.dyn_meta().is_untyped() {
733 // SAFETY: The metadata is coerceable and the struct is transmutable.
734 Ok(unsafe { core::mem::transmute::<Frame<FrameMeta>, UFrame>(dyn_frame) })
735 } else {
736 Err(dyn_frame)
737 }
738 }
739}*/
740
741} // verus!
742
743impl<M: AnyUFrameMeta> From<Frame<M>> for UFrame {
744 fn from(frame: Frame<M>) -> Self {
745 // SAFETY: The metadata is coerceable and the struct is transmutable.
746 unsafe { core::mem::transmute(frame) }
747 }
748}