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