ostd/mm/frame/unique.rs
1// SPDX-License-Identifier: MPL-2.0
2//! The unique frame pointer that is not shared with others.
3use vstd::atomic::PermissionU64;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
8
9use vstd_extra::cast_ptr::*;
10use vstd_extra::ownership::*;
11
12use super::meta::{AnyFrameMeta, GetFrameError, MetaSlot};
13
14use core::{marker::PhantomData, mem::ManuallyDrop, sync::atomic::Ordering};
15
16use super::meta::mapping::{
17 frame_to_index, frame_to_meta, max_meta_slots, meta_to_frame, META_SLOT_SIZE,
18};
19use super::meta::REF_COUNT_UNIQUE;
20use crate::mm::{Paddr, PagingLevel, MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
21use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
22use crate::specs::arch::paging_consts::PagingConsts;
23
24verus! {
25
26#[rustc_has_incoherent_inherent_impls]
27pub struct UniqueFrame<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
28 pub ptr: PPtr<MetaSlot>,
29 pub _marker: PhantomData<M>,
30}
31
32pub tracked struct UniqueFrameOwner<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
33 pub meta_own: M::Owner,
34 pub meta_perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, M>,
35 pub ghost slot_index: usize,
36}
37
38pub ghost struct UniqueFrameModel<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> {
39 pub meta: <M::Owner as View>::V,
40}
41
42impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> Inv for UniqueFrameOwner<M> {
43 open spec fn inv(self) -> bool {
44 &&& self.meta_perm.is_init()
45 &&& self.meta_perm.wf()
46 &&& self.slot_index == frame_to_index(meta_to_frame(self.meta_perm.addr()))
47 &&& self.slot_index < max_meta_slots()
48 &&& (self.slot_index - FRAME_METADATA_RANGE().start) as usize % META_SLOT_SIZE() == 0
49 &&& self.meta_perm.addr() < FRAME_METADATA_RANGE().start + MAX_NR_PAGES() * META_SLOT_SIZE()
50 }
51}
52
53impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> Inv for UniqueFrameModel<M> {
54 open spec fn inv(self) -> bool {
55 true
56 }
57}
58
59impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> View for UniqueFrameOwner<M> {
60 type V = UniqueFrameModel<M>;
61
62 open spec fn view(&self) -> Self::V {
63 UniqueFrameModel { meta: self.meta_own@ }
64 }
65}
66
67impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> InvView for UniqueFrameOwner<M> {
68 proof fn view_preserves_inv(self) {
69 }
70}
71
72impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> OwnerOf for UniqueFrame<M> {
73 type Owner = UniqueFrameOwner<M>;
74
75 open spec fn wf(self, owner: Self::Owner) -> bool {
76 &&& self.ptr.addr() == owner.meta_perm.addr()
77 }
78}
79
80impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> ModelOf for UniqueFrame<M> {
81
82}
83
84impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrameOwner<M> {
85 pub open spec fn perm_inv(self, perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
86 &&& perm.is_init()
87 &&& perm.value().storage.addr() == self.meta_perm.addr()
88 &&& perm.value().storage.addr() == self.meta_perm.points_to.addr()
89 }
90
91 pub open spec fn global_inv(self, regions: MetaRegionOwners) -> bool {
92 &&& regions.slots.contains_key(self.slot_index) ==> self.perm_inv(
93 regions.slots[self.slot_index],
94 )
95 &&& regions.dropped_slots.contains_key(self.slot_index) ==> self.perm_inv(
96 regions.dropped_slots[self.slot_index],
97 )
98 }
99
100 pub proof fn from_raw_owner(
101 owner: M::Owner,
102 index: Ghost<usize>,
103 perm: vstd_extra::cast_ptr::PointsTo<MetaSlot, M>,
104 ) -> Self {
105 UniqueFrameOwner::<M> { meta_own: owner, meta_perm: perm, slot_index: index@ }
106 }
107}
108
109impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrame<M> {
110 /// Gets a [`UniqueFrame`] with a specific usage from a raw, unused page.
111 ///
112 /// The caller should provide the initial metadata of the page.
113 #[rustc_allow_incoherent_impl]
114 #[verus_spec(
115 with Tracked(regions): Tracked<&mut MetaRegionOwners>
116 )]
117 pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError>
118 requires
119 paddr < MAX_PADDR(),
120 paddr % PAGE_SIZE() == 0,
121 old(regions).slots.contains_key(frame_to_meta(paddr)),
122 old(regions).inv(),
123 {
124 #[verus_spec(with Tracked(regions))]
125 let from_unused = MetaSlot::get_from_unused(paddr, metadata, true);
126 Ok(Self { ptr: from_unused?, _marker: PhantomData })
127 }
128
129 /*
130 /// Repurposes the frame with a new metadata.
131 pub fn repurpose<M1: AnyFrameMeta>(self, metadata: M1) -> UniqueFrame<M1> {
132 // SAFETY: We are the sole owner and the metadata is initialized.
133 unsafe { self.slot().drop_meta_in_place() };
134 // SAFETY: We are the sole owner.
135 unsafe { self.slot().write_meta(metadata) };
136 // SAFETY: The metadata is initialized with type `M1`.
137 unsafe { core::mem::transmute(self) }
138 }*/
139 /// Gets the metadata of this page.
140 #[rustc_allow_incoherent_impl]
141 #[verifier::external_body]
142 pub fn meta(&self) -> (l: &M)
143 ensures
144 // perm.mem_contents().value() == l,
145
146 {
147 unimplemented!()
148 // SAFETY: The type is tracked by the type system.
149 // unsafe { &*self.slot().as_meta_ptr() }
150
151 }
152
153 /// Gets the mutable metadata of this page.
154 #[rustc_allow_incoherent_impl]
155 #[verus_spec(
156 with Tracked(perm) : Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
157 )]
158 #[verifier::external_body]
159 pub fn meta_mut(&mut self) -> (res: ReprPtr<MetaSlot, M>)
160 requires
161 // perm.is_init(),
162 // perm.pptr() == old(self).ptr,
163 // perm.value().wf(owner)
164
165 ensures
166 res.addr() == self.ptr.addr(),
167 res.ptr.addr() == self.ptr.addr(),
168 *self == *old(self),
169 {
170 // SAFETY: The type is tracked by the type system.
171 // And we have the exclusive access to the metadata.
172 // let owner = regions.slot_owners.tracked_remove(frame_to_index(meta_to_frame(self.ptr.addr())));
173 // let perm = owner.cast_perm();
174 // regions.slot_owners.tracked_insert(frame_to_index(meta_to_frame(self.ptr.addr())), owner);
175 #[verus_spec(with Tracked(perm))]
176 let slot = self.slot();
177
178 #[verus_spec(with Tracked(perm))]
179 slot.as_meta_ptr()
180 }
181}
182
183impl<M: AnyFrameMeta + Repr<MetaSlot> + OwnerOf> UniqueFrame<M> {
184 /// Gets the physical address of the start of the frame.
185 #[rustc_allow_incoherent_impl]
186 #[verus_spec(
187 with Tracked(regions) : Tracked<& MetaRegionOwners>
188 )]
189 #[verifier::external_body]
190 pub fn start_paddr(&self) -> Paddr {
191 // #[verus_spec(with Tracked(®ions))]
192 let slot = self.slot();
193 slot.frame_paddr()
194 }
195
196 /// Gets the paging level of this page.
197 ///
198 /// This is the level of the page table entry that maps the frame,
199 /// which determines the size of the frame.
200 ///
201 /// Currently, the level is always 1, which means the frame is a regular
202 /// page frame.
203 #[rustc_allow_incoherent_impl]
204 pub const fn level(&self) -> PagingLevel {
205 1
206 }
207
208 /// Gets the size of this page in bytes.
209 #[rustc_allow_incoherent_impl]
210 pub const fn size(&self) -> usize {
211 PAGE_SIZE()
212 }
213
214 /* /// Gets the dynamically-typed metadata of this frame.
215 ///
216 /// If the type is known at compile time, use [`Frame::meta`] instead.
217 #[rustc_allow_incoherent_impl]
218 #[verifier::external_body]
219 pub fn dyn_meta(&self) -> &M {
220 // SAFETY: The metadata is initialized and valid.
221 unsafe { &*self.slot().dyn_meta_ptr::<M>() }
222 }
223
224 /// Gets the dynamically-typed metadata of this frame.
225 ///
226 /// If the type is known at compile time, use [`Frame::meta`] instead.
227 #[rustc_allow_incoherent_impl]
228 #[verifier::external_body]
229 pub fn dyn_meta_mut(&mut self) -> &mut FrameMeta {
230 // SAFETY: The metadata is initialized and valid. We have the exclusive
231 // access to the frame.
232 unsafe { &mut *self.slot().dyn_meta_ptr() }
233 }*/
234 /*
235 /// Resets the frame to unused without up-calling the allocator.
236 ///
237 /// This is solely useful for the allocator implementation/testing and
238 /// is highly experimental. Usage of this function is discouraged.
239 ///
240 /// Usage of this function other than the allocator would actually leak
241 /// the frame since the allocator would not be aware of the frame.
242 //
243 // FIXME: We may have a better `Segment` and `UniqueSegment` design to
244 // allow the allocator hold the ownership of all the frames in a chunk
245 // instead of the head. Then this weird public API can be `#[cfg(ktest)]`.
246 pub fn reset_as_unused(self) {
247 let this = ManuallyDrop::new(self);
248
249 this.slot().ref_count.store(0, Ordering::Release);
250 // SAFETY: We are the sole owner and the reference count is 0.
251 // The slot is initialized.
252 unsafe { this.slot().drop_last_in_place() };
253 }*/
254 /// Converts this frame into a raw physical address.
255 #[rustc_allow_incoherent_impl]
256 #[verifier::external_body]
257 pub(crate) fn into_raw(self) -> Paddr {
258 let this = ManuallyDrop::new(self);
259 this.start_paddr()
260 }
261
262 /// Restores a raw physical address back into a unique frame.
263 ///
264 /// # Safety
265 ///
266 /// The caller must ensure that the physical address is valid and points to
267 /// a forgotten frame that was previously casted by [`Self::into_raw`].
268 #[rustc_allow_incoherent_impl]
269 #[verus_spec(res =>
270 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
271 Tracked(meta_perm): Tracked<PointsTo<MetaSlot, M>>,
272 Tracked(meta_own): Tracked<M::Owner>
273 )]
274 #[verifier::external_body]
275 pub fn from_raw(paddr: Paddr) -> (res: (Self, Tracked<UniqueFrameOwner<M>>))
276 requires
277 paddr < MAX_PADDR(),
278 paddr % PAGE_SIZE() == 0,
279 old(regions).dropped_slots.contains_key(frame_to_index(paddr)),
280 ensures
281 res.0.ptr.addr() == frame_to_meta(paddr),
282 res.0.wf(res.1@),
283 res.1@.meta_own == meta_own,
284 res.1@.meta_perm == meta_perm,
285 regions.slots[frame_to_index(paddr)] == old(regions).dropped_slots[frame_to_index(
286 paddr,
287 )],
288 !regions.dropped_slots.contains_key(frame_to_index(paddr)),
289 regions.slots == old(regions).slots,
290 regions.slot_owners == old(regions).slot_owners,
291 {
292 let vaddr = frame_to_meta(paddr);
293 let ptr = vstd::simple_pptr::PPtr::<MetaSlot>::from_addr(vaddr);
294
295 let tracked slot_own = regions.dropped_slots.tracked_remove(frame_to_index(paddr));
296 proof { regions.slots.tracked_insert(frame_to_index(paddr), slot_own) }
297
298 (
299 Self { ptr, _marker: PhantomData },
300 Tracked(
301 UniqueFrameOwner::<M>::from_raw_owner(
302 meta_own,
303 Ghost(frame_to_index(paddr)),
304 meta_perm,
305 ),
306 ),
307 )
308 }
309
310 #[rustc_allow_incoherent_impl]
311 #[verifier::external_body]
312 #[verus_spec(
313 with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
314 )]
315 pub fn slot<'a>(&self) -> &'a MetaSlot
316 requires
317 slot_perm.pptr() == self.ptr,
318 slot_perm.is_init(),
319 returns
320 slot_perm.value(),
321 {
322 unimplemented!()
323 // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
324 // mutably borrowed, so taking an immutable reference to it is safe.
325 // unsafe { &*self.ptr }
326
327 }
328}
329
330/*impl<M: AnyFrameMeta + ?Sized> Drop for UniqueFrame<M> {
331 fn drop(&mut self) {
332 self.slot().ref_count.store(0, Ordering::Relaxed);
333 // SAFETY: We are the sole owner and the reference count is 0.
334 // The slot is initialized.
335 unsafe { self.slot().drop_last_in_place() };
336
337 super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
338 }
339}*/
340/*impl<M: AnyFrameMeta> From<UniqueFrame<Link<M>>> for Frame<M> {
341 #[verifier::external_body]
342 fn from(unique: UniqueFrame<Link<M>>) -> Self {
343 unimplemented!()/*
344 // The `Release` ordering make sure that previous writes are visible
345 // before the reference count is set to 1. It pairs with
346 // `MetaSlot::get_from_in_use`.
347 unique.slot().ref_count.store(1, Ordering::Release);
348 // SAFETY: The internal representation is now the same.
349 unsafe { core::mem::transmute(unique) }*/
350
351 }
352}*/
353/*impl<M: AnyFrameMeta> TryFrom<Frame<M>> for UniqueFrame<Link<M>> {
354 type Error = Frame<M>;
355
356 #[verifier::external_body]
357 /// Tries to get a unique frame from a shared frame.
358 ///
359 /// If the reference count is not 1, the frame is returned back.
360 fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
361 unimplemented!()/* match frame.slot().ref_count.compare_exchange(
362 1,
363 REF_COUNT_UNIQUE,
364 Ordering::Relaxed,
365 Ordering::Relaxed,
366 ) {
367 Ok(_) => {
368 // SAFETY: The reference count is now `REF_COUNT_UNIQUE`.
369 Ok(unsafe { core::mem::transmute::<Frame<M>, UniqueFrame<M>>(frame) })
370 }
371 Err(_) => Err(frame),
372 }*/
373
374 }
375}*/
376} // verus!