1pub 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 mem::ManuallyDrop,
54 sync::atomic::{AtomicUsize, Ordering},
55};
56
57use meta::REF_COUNT_UNUSED;
59pub use segment::Segment;
60
61use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
63pub use frame_ref::FrameRef;
64pub use linked_list::{CursorMut, Link, LinkedList};
65pub use meta::mapping::{
66 frame_to_index, frame_to_index_spec, frame_to_meta, meta_to_frame, META_SLOT_SIZE,
67};
68pub use meta::{AnyFrameMeta, GetFrameError, MetaSlot, MetaSlotStorage, StoredPageTablePageMeta};
69pub use unique::{UniqueFrame, UniqueFrameOwner};
70
71use crate::mm::page_table::{PageTableConfig, PageTablePageMeta};
72
73use vstd_extra::cast_ptr::*;
74use vstd_extra::ownership::*;
75use vstd_extra::undroppable::*;
76
77use crate::mm::{kspace::LINEAR_MAPPING_BASE_VADDR, Paddr, PagingLevel, Vaddr, MAX_PADDR};
78use crate::specs::arch::{
79 kspace::VMALLOC_BASE_VADDR,
80 mm::{MAX_NR_PAGES, PAGE_SIZE},
81};
82use crate::specs::mm::frame::meta_owners::MetaSlotOwner;
83use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
84
85verus! {
86
87pub type MetaPerm<M> = cast_ptr::PointsTo<MetaSlot, M>;
92
93#[repr(transparent)]
102#[rustc_has_incoherent_inherent_impls]
103pub struct Frame<M: AnyFrameMeta> {
104 pub ptr: PPtr<MetaSlot>,
105 pub _marker: PhantomData<M>,
106}
107
108impl<M: AnyFrameMeta> Clone for Frame<M> {
109 fn clone(&self) -> Self {
110 Self { ptr: PPtr::<MetaSlot>::from_addr(self.ptr.0), _marker: PhantomData }
111 }
112}
113
114impl<M: AnyFrameMeta> Undroppable for Frame<M> {
115 type State = MetaRegionOwners;
116
117 open spec fn constructor_requires(self, s: Self::State) -> bool {
118 &&& s.slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
119 &&& !s.dropped_slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
120 &&& s.inv()
121 }
122
123 open spec fn constructor_ensures(self, s0: Self::State, s1: Self::State) -> bool {
124 &&& !s1.slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
125 &&& s1.dropped_slots.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
126 &&& s0.slot_owners == s1.slot_owners
127 &&& forall|i: usize|
128 i != frame_to_index(meta_to_frame(self.ptr.addr())) ==> s0.dropped_slots[i]
129 == s1.dropped_slots[i] && s0.slots[i] == s1.slots[i]
130 &&& s1.dropped_slots[frame_to_index(meta_to_frame(self.ptr.addr()))]
131 == s0.slots[frame_to_index(meta_to_frame(self.ptr.addr()))]
132 &&& s1.inv()
133 }
134
135 proof fn constructor_spec(self, tracked s: &mut Self::State) {
136 let meta_addr = self.ptr.addr();
137 let index = frame_to_index(meta_to_frame(meta_addr));
138 let tracked perm = s.slots.tracked_remove(index);
139 s.dropped_slots.tracked_insert(index, perm);
140 }
141}
142
143impl<M: AnyFrameMeta> cast_ptr::Repr<MetaSlot> for Frame<M> {
144 open spec fn wf(m: MetaSlot) -> bool {
145 true }
148
149 open spec fn to_repr_spec(self) -> MetaSlot {
150 arbitrary() }
153
154 open spec fn from_repr_spec(r: MetaSlot) -> Self {
155 arbitrary() }
158
159 #[verifier::external_body]
160 fn to_repr(self) -> (res: MetaSlot)
161 ensures
162 res == self.to_repr_spec(),
163 {
164 unimplemented!()
165 }
166
167 #[verifier::external_body]
168 fn from_repr(r: MetaSlot) -> (res: Self)
169 ensures
170 res == Self::from_repr_spec(r),
171 {
172 unimplemented!()
173 }
174
175 #[verifier::external_body]
176 fn from_borrowed<'a>(r: &'a MetaSlot) -> (res: &'a Self)
177 ensures
178 *res == Self::from_repr_spec(*r),
179 {
180 unimplemented!()
181 }
182
183 proof fn from_to_repr(self)
184 ensures
185 Self::from_repr(self.to_repr()) == self,
186 {
187 admit();
188 }
189
190 proof fn to_from_repr(r: MetaSlot)
191 ensures
192 Self::from_repr(r).to_repr() == r,
193 {
194 admit();
195 }
196
197 proof fn to_repr_wf(self)
198 ensures
199 Self::wf(self.to_repr()),
200 {
201 admit();
202 }
203}
204
205impl<M: AnyFrameMeta> Inv for Frame<M> {
206 open spec fn inv(self) -> bool {
207 &&& self.ptr.addr() % META_SLOT_SIZE() == 0
208 &&& FRAME_METADATA_RANGE().start <= self.ptr.addr() < FRAME_METADATA_RANGE().start
209 + MAX_NR_PAGES() * META_SLOT_SIZE()
210 &&& self.ptr.addr() < VMALLOC_BASE_VADDR() - LINEAR_MAPPING_BASE_VADDR()
211 }
212}
213
214impl<M: AnyFrameMeta> Frame<M> {
215 pub open spec fn paddr(self) -> usize {
216 meta_to_frame(self.ptr.addr())
217 }
218
219 pub open spec fn index(self) -> usize {
220 frame_to_index(self.paddr())
221 }
222
223 #[verifier::external_body]
224 pub fn meta_pt<'a, C: PageTableConfig>(
225 &'a self,
226 Tracked(p_slot): Tracked<&'a simple_pptr::PointsTo<MetaSlot>>,
227 owner:
228 MetaSlotOwner,
229 ) -> (res: &'a PageTablePageMeta<C>)
231 requires
232 self.inv(),
233 p_slot.pptr() == self.ptr,
234 p_slot.is_init(),
235 p_slot.value().wf(owner),
236 is_variant(owner.view().storage.value(), "PTNode"),
237 ensures
238 {
241 let slot = self.ptr.borrow(Tracked(p_slot));
242 unimplemented!()
243 }
246}
247
248#[verus_verify]
268impl<'a, M: AnyFrameMeta> Frame<M> {
269 #[rustc_allow_incoherent_impl]
270 pub open spec fn from_unused_requires(
271 regions: MetaRegionOwners,
272 paddr: Paddr,
273 metadata: M,
274 ) -> bool {
275 &&& paddr % PAGE_SIZE() == 0
276 &&& paddr < MAX_PADDR()
277 &&& regions.slots.contains_key(frame_to_index(paddr))
278 &&& regions.slot_owners[frame_to_index(paddr)].usage is Unused
279 &&& regions.slot_owners[frame_to_index(paddr)].in_list.points_to(0)
280 &&& regions.slot_owners[frame_to_index(paddr)].self_addr == frame_to_meta(paddr)
281 &&& regions.inv()
282 }
283
284 #[rustc_allow_incoherent_impl]
285 pub open spec fn from_unused_ensures(
286 old_regions: MetaRegionOwners,
287 new_regions: MetaRegionOwners,
288 paddr: Paddr,
289 metadata: M,
290 r: Self,
291 ) -> bool {
292 &&& new_regions@ == MetaSlot::get_from_unused_spec::<M>(
293 paddr,
294 metadata,
295 false,
296 old_regions@,
297 ).1
298 &&& new_regions.inv()
299 &&& forall|paddr: Paddr| #[trigger]
300 old_regions.slots.contains_key(frame_to_index(paddr))
301 ==> new_regions.slots.contains_key(frame_to_index(paddr))
302 }
303
304 #[verus_spec(r =>
312 with
313 Tracked(regions): Tracked<&mut MetaRegionOwners>,
314 requires
315 Self::from_unused_requires(*old(regions), paddr, metadata),
316 ensures
317 r matches Ok(r) ==> Self::from_unused_ensures(*old(regions), *regions, paddr, metadata, r),
318 )]
319 #[rustc_allow_incoherent_impl]
320 #[verifier::external_body]
321 pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
322 #[verus_spec(with Tracked(regions))]
323 let from_unused = MetaSlot::get_from_unused(paddr, metadata, false);
324 Ok(Self { ptr: from_unused?, _marker: PhantomData })
325 }
326
327 #[verus_spec(
329 with Tracked(perm) : Tracked<&'a PointsTo<MetaSlot, M>>,
330 requires
331 self.ptr.addr() == perm.addr(),
332 self.ptr == perm.points_to.pptr(),
333 perm.is_init(),
334 perm.wf(),
335 returns
336 perm.value(),
337 )]
338 #[rustc_allow_incoherent_impl]
339 pub fn meta(&self) -> &'a M {
340 #[verus_spec(with Tracked(&perm.points_to))]
342 let slot = self.slot();
343
344 #[verus_spec(with Tracked(&perm.points_to))]
345 let ptr = slot.as_meta_ptr();
346
347 ptr.borrow(Tracked(perm))
348 }
349}
350
351#[verus_verify]
352impl<M: AnyFrameMeta> Frame<M> {
353 #[verus_spec(
359 with Tracked(regions) : Tracked<&mut MetaRegionOwners>
360 )]
361 #[rustc_allow_incoherent_impl]
362 pub fn from_in_use(paddr: Paddr) -> Result<Self, GetFrameError> {
363 #[verus_spec(with Tracked(regions))]
364 let from_in_use = MetaSlot::get_from_in_use(paddr);
365 Ok(Self { ptr: from_in_use?, _marker: PhantomData })
366 }
367
368 #[rustc_allow_incoherent_impl]
369 pub open spec fn from_raw_requires(regions: MetaRegionOwners, paddr: Paddr) -> bool {
370 &&& paddr % PAGE_SIZE() == 0
371 &&& !regions.slots.contains_key(frame_to_index(paddr))
373 &&& regions.dropped_slots.contains_key(frame_to_index(paddr))
374 &&& regions.inv()
375 }
376
377 #[rustc_allow_incoherent_impl]
378 pub open spec fn from_raw_ensures(
379 old_regions: MetaRegionOwners,
380 new_regions: MetaRegionOwners,
381 paddr: Paddr,
382 r: Self,
383 ) -> bool {
384 &&& new_regions.inv()
385 &&& new_regions.slots.contains_key(frame_to_index(paddr))
386 &&& !new_regions.dropped_slots.contains_key(frame_to_index(paddr))
387 &&& new_regions.slots[frame_to_index(paddr)] == old_regions.dropped_slots[frame_to_index(
388 paddr,
389 )]
390 &&& forall|i: usize|
391 #![trigger new_regions.slots[i], old_regions.slots[i]]
392 i != frame_to_index(paddr) ==> new_regions.slots[i] == old_regions.slots[i]
393 &&& forall|i: usize|
394 #![trigger new_regions.dropped_slots[i], old_regions.dropped_slots[i]]
395 i != frame_to_index(paddr) ==> new_regions.dropped_slots[i]
396 == old_regions.dropped_slots[i]
397 &&& new_regions.slot_owners == old_regions.slot_owners
398 &&& r.ptr == new_regions.slots[frame_to_index(paddr)].pptr()
399 &&& r.paddr() == paddr
400 }
401
402 #[rustc_allow_incoherent_impl]
403 pub open spec fn into_raw_requires(self, regions: MetaRegionOwners) -> bool {
404 &&& regions.slots.contains_key(self.index())
405 &&& !regions.dropped_slots.contains_key(self.index())
406 &&& regions.inv()
407 }
408
409 #[rustc_allow_incoherent_impl]
410 pub open spec fn into_raw_ensures(
411 self,
412 regions: MetaRegionOwners,
413 r: Paddr,
414 perm: MetaPerm<M>,
415 ) -> bool {
416 &&& r == meta_to_frame(self.ptr.addr())
417 &&& regions.slot_owners == regions.slot_owners
418 &&& regions.dropped_slots == regions.dropped_slots
419 &&& forall|i: usize|
420 #![trigger frame_to_index(self.ptr.addr()), regions.slots[i]]
421 i != frame_to_index(self.ptr.addr()) ==> regions.slots[i] == regions.slots[i]
422 }
423}
424
425#[verus_verify]
426impl<'a, M: AnyFrameMeta> Frame<M> {
427 #[verus_spec(
429 with Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>
430 )]
431 #[rustc_allow_incoherent_impl]
432 pub fn start_paddr(&self) -> Paddr
433 requires
434 perm.addr() == self.ptr.addr(),
435 perm.is_init(),
436 FRAME_METADATA_RANGE().start <= perm.addr() < FRAME_METADATA_RANGE().end,
437 perm.addr() % META_SLOT_SIZE() == 0,
438 returns
439 meta_to_frame(self.ptr.addr()),
440 {
441 #[verus_spec(with Tracked(perm))]
442 let slot = self.slot();
443
444 #[verus_spec(with Tracked(perm))]
445 slot.frame_paddr()
446 }
447
448 #[rustc_allow_incoherent_impl]
456 pub const fn map_level(&self) -> PagingLevel {
457 1
458 }
459
460 #[rustc_allow_incoherent_impl]
462 pub const fn size(&self) -> usize {
463 PAGE_SIZE()
464 }
465
466 #[verus_spec(
485 with Tracked(slot_own): Tracked<&mut MetaSlotOwner>,
486 Tracked(slot_perm) : Tracked<& vstd::simple_pptr::PointsTo<MetaSlot>>
487 )]
488 #[rustc_allow_incoherent_impl]
489 pub fn reference_count(&self) -> u64
490 requires
491 slot_perm.pptr() == self.ptr,
492 slot_perm.is_init(),
493 old(slot_own).ref_count.is_for(slot_perm.value().ref_count),
494 returns
495 old(slot_own)@.ref_count,
496 {
497 #[verus_spec(with Tracked(slot_perm))]
498 let slot = self.slot();
499 slot.ref_count.load(Tracked(&slot_own.ref_count))
500 }
501
502 #[rustc_allow_incoherent_impl]
504 #[verus_spec(res =>
505 with Tracked(regions): Tracked<&mut MetaRegionOwners>,
506 Tracked(perm): Tracked<&MetaPerm<M>>,
507 requires
508 old(regions).inv(),
509 self.paddr() % PAGE_SIZE() == 0,
510 self.paddr() < MAX_PADDR(),
511 !old(regions).slots.contains_key(self.index()),
512 perm.points_to.pptr() == self.ptr,
513 perm.is_init(),
514 FRAME_METADATA_RANGE().start <= perm.points_to.addr() < FRAME_METADATA_RANGE().end,
515 perm.points_to.addr() % META_SLOT_SIZE() == 0,
516 ensures
517 regions.inv(),
518 res.inner@.ptr.addr() == self.ptr.addr(),
519 )]
520 #[verifier::external_body]
521 pub fn borrow(&self) -> FrameRef<'a, M> {
522 assert(regions.slot_owners.contains_key(self.index()));
523 #[verus_spec(with Tracked(&perm.points_to))]
525 let paddr = self.start_paddr();
526
527 #[verus_spec(with Tracked(regions), Tracked(perm))]
528 FrameRef::borrow_paddr(paddr)
529 }
530
531 #[verus_spec(r =>
539 with
540 Tracked(regions): Tracked<&mut MetaRegionOwners>,
541 -> frame_perm: Tracked<MetaPerm<M>>,
542 requires
543 Self::into_raw_requires(self, *old(regions)),
544 ensures
545 Self::into_raw_ensures(self, *regions, r, frame_perm@),
546 )]
547 #[rustc_allow_incoherent_impl]
548 pub fn into_raw(self) -> Paddr {
549 assert(regions.slots[self.index()].addr() == self.paddr()) by { admit() };
550
551 let tracked owner = regions.slot_owners.tracked_borrow(self.index());
552 let tracked perm = regions.slots.tracked_remove(self.index());
553
554 #[verus_spec(with Tracked(&perm))]
555 let paddr = self.start_paddr();
556
557 let tracked meta_perm = PointsTo::<MetaSlot, M>::new(Ghost(self.ptr.addr()), perm);
558
559 proof_with!(|= Tracked(meta_perm));
563 paddr
564 }
565
566 #[rustc_allow_incoherent_impl]
579 #[verifier::external_body]
580 #[verus_spec(r =>
581 with
582 Tracked(regions): Tracked<&mut MetaRegionOwners>,
583 Tracked(perm): Tracked<&MetaPerm<M>>,
584 requires
585 Self::from_raw_requires(*old(regions), paddr),
586 ensures
587 Self::from_raw_ensures(*old(regions), *regions, paddr, r),
588 )]
589 pub fn from_raw(paddr: Paddr) -> Self {
590 let vaddr = frame_to_meta(paddr);
591 let ptr = PPtr::from_addr(vaddr);
592
593 proof {
594 regions.slots.tracked_insert(frame_to_index(paddr), perm.points_to);
595 }
596
597 Self { ptr, _marker: PhantomData }
598 }
599
600 #[verus_spec(
601 with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
602 )]
603 #[rustc_allow_incoherent_impl]
604 pub fn slot(&self) -> (slot: &'a MetaSlot)
605 requires
606 slot_perm.pptr() == self.ptr,
607 slot_perm.is_init(),
608 returns
609 slot_perm.value(),
610 {
611 self.ptr.borrow(Tracked(slot_perm))
614 }
615}
616
617} #[verifier::external_body]
708pub(in crate::mm) unsafe fn inc_frame_ref_count(paddr: Paddr) {
709 debug_assert!(paddr % PAGE_SIZE() == 0);
710
711 let vaddr: Vaddr = frame_to_meta(paddr);
712 let slot = unsafe { &*(vaddr as *const MetaSlot) };
715
716 slot.inc_ref_count();
718}