ostd/specs/mm/frame/
meta_specs.rs1use vstd::atomic::*;
2use vstd::atomic::*;
3use vstd::cell;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use vstd_extra::cast_ptr::*;
8use vstd_extra::ownership::*;
9
10use super::meta_owners::{
11 MetaSlotModel, MetaSlotOwner, MetaSlotStatus, MetaSlotStorage, Metadata, PageUsage,
12};
13use crate::mm::frame::meta::{
14 get_slot_spec,
15 mapping::{frame_to_index, frame_to_meta},
16 REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
17};
18use crate::mm::frame::*;
19use crate::mm::{Paddr, PagingLevel, Vaddr};
20use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
21use crate::specs::arch::mm::{MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
22use crate::specs::mm::frame::meta_owners::MetadataInnerPerms;
23use crate::specs::mm::frame::meta_region_owners::{MetaRegionModel, MetaRegionOwners};
24
25use core::marker::PhantomData;
26
27verus! {
28
29impl MetaSlot {
30 pub open spec fn get_from_unused_inner_perms_spec(
31 as_unique: bool,
32 perms: MetadataInnerPerms,
33 ) -> bool {
34 &&& perms.ref_count.value() == (if as_unique {
35 REF_COUNT_UNIQUE as u64
36 } else {
37 1u64
38 })
39 &&& perms.in_list.value() == 0
40 &&& perms.storage.is_init()
41 &&& perms.vtable_ptr.is_init()
42 }
43
44 pub open spec fn get_from_unused_spec(
45 paddr: Paddr,
46 as_unique: bool,
47 pre: MetaRegionOwners,
48 post: MetaRegionOwners,
49 ) -> bool
50 recommends
51 paddr % PAGE_SIZE == 0,
52 paddr < MAX_PADDR,
53 pre.inv(),
54 {
55 let idx = frame_to_index(paddr);
56 {
57 &&& post.slots =~= pre.slots.remove(idx)
58 &&& MetaSlot::get_from_unused_inner_perms_spec(
59 as_unique,
60 post.slot_owners[idx].inner_perms,
61 )
62 &&& post.slot_owners[idx].usage == PageUsage::Frame
63 &&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
64 &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
65 &&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
66 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
67 &&& pre.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED
68 }
69 }
70
71 pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
72 paddr: Paddr,
73 metadata: M,
74 as_unique: bool,
75 ptr: PPtr<MetaSlot>,
76 perm: PointsTo<MetaSlot, Metadata<M>>,
77 ) -> bool {
78 &&& ptr.addr() == frame_to_meta(paddr)
79 &&& perm.addr() == frame_to_meta(paddr)
80 &&& perm.is_init()
81 &&& perm.wf(&perm.inner_perms)
82 &&& MetaSlot::get_from_unused_inner_perms_spec(as_unique, perm.inner_perms)
83 }
84
85 pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
86 rc_perm.value() >= REF_COUNT_MAX
87 }
88
89 pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
90 &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
91 &&& perm.addr() % META_SLOT_SIZE == 0
92 }
93
94 pub open spec fn get_from_in_use_panic_cond(paddr: Paddr, regions: MetaRegionOwners) -> bool {
95 let idx = frame_to_index(paddr);
96 let pre_perms = regions.slot_owners[idx].inner_perms.ref_count.value();
97 pre_perms + 1 >= REF_COUNT_MAX
98 }
99
100 pub open spec fn get_from_in_use_success(
101 paddr: Paddr,
102 pre: MetaRegionOwners,
103 post: MetaRegionOwners,
104 ) -> bool
105 recommends
106 paddr % PAGE_SIZE == 0,
107 paddr < MAX_PADDR,
108 pre.inv(),
109 {
110 let idx = frame_to_index(paddr);
111 let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
112 {
113 &&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
114 &&& post.slot_owners[idx].inner_perms.ref_count.id()
115 == pre.slot_owners[idx].inner_perms.ref_count.id()
116 &&& post.slot_owners[idx].inner_perms.storage
117 == pre.slot_owners[idx].inner_perms.storage
118 &&& post.slot_owners[idx].inner_perms.vtable_ptr
119 == pre.slot_owners[idx].inner_perms.vtable_ptr
120 &&& post.slot_owners[idx].inner_perms.in_list
121 == pre.slot_owners[idx].inner_perms.in_list
122 &&& post.slot_owners[idx].self_addr == pre.slot_owners[idx].self_addr
123 &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
124 &&& post.slot_owners[idx].raw_count == pre.slot_owners[idx].raw_count
125 &&& post.slot_owners[idx].path_if_in_pt == pre.slot_owners[idx].path_if_in_pt
126 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
127 }
128 }
129
130 pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
131 &&& (owner.inner_perms.ref_count.value() == 0 || owner.inner_perms.ref_count.value()
132 == REF_COUNT_UNIQUE)
133 &&& owner.inner_perms.storage.is_init()
134 &&& owner.inner_perms.in_list.value() == 0
135 &&& owner.raw_count == 0
136 }
137
138 pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
139 recommends
140 pre.inv(),
141 pre.status == MetaSlotStatus::SHARED,
142 {
143 MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
144 }
145}
146
147impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
148 pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
149 Frame::<M> {
150 ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
151 _marker: PhantomData,
152 }
153 }
154}
155
156}