ostd/specs/mm/frame/
meta_specs.rs1use core::marker::PhantomData;
2
3use vstd::prelude::*;
4
5use vstd::{
6 atomic::*,
7 simple_pptr::{self, PPtr},
8};
9use vstd_extra::{cast_ptr::*, ownership::*};
10
11use crate::specs::{
12 arch::*,
13 mm::frame::{
14 mapping::{frame_to_index, index_to_meta},
15 meta_owners::MetadataInnerPerms,
16 meta_region_owners::MetaRegionOwners,
17 },
18};
19
20use crate::mm::{
21 Paddr, PagingLevel, Vaddr,
22 frame::{
23 meta::{
24 META_SLOT_SIZE, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
25 mapping::{frame_to_meta, meta_to_frame},
26 },
27 *,
28 },
29 kspace::FRAME_METADATA_RANGE,
30};
31
32use super::meta_owners::{
33 MetaSlotModel, MetaSlotOwner, MetaSlotStatus, MetaSlotStorage, Metadata, PageUsage,
34};
35
36verus! {
37
38global layout MetaSlot is size == 64, align == 8;
39
40impl MetaSlot {
41 pub proof fn lemma_layout()
42 ensures
43 core::mem::size_of::<MetaSlot>() == META_SLOT_SIZE,
44 vstd::layout::size_of::<MetaSlot>() == META_SLOT_SIZE,
45 {
46 broadcast use VERUS_layout_of_MetaSlot;
47
48 }
49
50 #[verus_spec(res =>
52 with
53 Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>,
54 requires
55 perm.value() == self,
56 addr == perm.addr(),
57 ensures
58 res.ptr.addr() == addr,
59 res.addr() == addr,
60 )]
61 pub fn cast_slot<M: AnyFrameMeta + Repr<MetaSlotStorage>>(&self, addr: usize) -> ReprPtr<
62 MetaSlot,
63 Metadata<M>,
64 > {
65 ReprPtr::<MetaSlot, Metadata<M>> { ptr: PPtr::from_addr(addr), _T: PhantomData }
66 }
67
68 pub open spec fn get_from_unused_inner_perms_spec(
69 as_unique: bool,
70 perms: MetadataInnerPerms,
71 ) -> bool {
72 &&& perms.ref_count.value() == (if as_unique {
73 REF_COUNT_UNIQUE as u64
74 } else {
75 1u64
76 })
77 &&& perms.in_list.value() == 0
78 &&& perms.storage.is_init()
79 &&& perms.vtable_ptr.is_init()
80 }
81
82 pub open spec fn get_from_unused_spec(
84 paddr: Paddr,
85 as_unique: bool,
86 pre: MetaRegionOwners,
87 post: MetaRegionOwners,
88 ) -> bool
89 recommends
90 valid_frame_paddr(paddr),
91 pre.inv(),
92 {
93 let idx = frame_to_index(paddr);
94 let pre_owner = pre.slot_owners[idx];
95 let post_owner = post.slot_owners[idx];
96 {
97 &&& pre_owner.inner_perms.ref_count.value() == REF_COUNT_UNUSED
98 &&& MetaSlot::get_from_unused_inner_perms_spec(as_unique, post_owner.inner_perms)
99 &&& post_owner.usage is Frame
100 &&& post_owner.slot_vaddr == pre_owner.slot_vaddr
101 &&& post_owner.paths_in_pt == pre_owner.paths_in_pt
102 &&& post =~= pre.insert_slot_owner(paddr, post_owner)
103 }
104 }
105
106 pub open spec fn get_node_from_unused_spec(
114 paddr: Paddr,
115 pre: MetaRegionOwners,
116 post: MetaRegionOwners,
117 ) -> bool
118 recommends
119 valid_frame_paddr(paddr),
120 pre.inv(),
121 {
122 let idx = frame_to_index(paddr);
123 {
124 &&& post.slot_owners.dom() =~= pre.slot_owners.dom()
125 &&& MetaSlot::get_from_unused_inner_perms_spec(false, post.slot_owners[idx].inner_perms)
126 &&& post.slot_owners[idx].usage is PageTable
127 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
128 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
129 &&& forall|i: int| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
130 &&& pre.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED
131 }
132 }
133
134 pub open spec fn slot_perm_reparked_spec(
141 paddr: Paddr,
142 pre: MetaRegionOwners,
143 post: MetaRegionOwners,
144 ) -> bool {
145 let idx = frame_to_index(paddr);
146 &&& post.slots.dom() =~= pre.slots.dom()
147 &&& forall|k: int|
148 #![trigger post.slots[k]]
149 k != idx && pre.slots.contains_key(k) ==> post.slots[k] == pre.slots[k]
150 }
151
152 pub open spec fn live_frame_obligations_ok_spec(
158 paddr: Paddr,
159 pre: MetaRegionOwners,
160 post: MetaRegionOwners,
161 ) -> bool {
162 &&& post.frame_obligations =~= pre.frame_obligations.insert(frame_to_index(paddr))
163 }
164
165 pub open spec fn live_frame_obligations_err_spec(
168 pre: MetaRegionOwners,
169 post: MetaRegionOwners,
170 ) -> bool {
171 &&& post.frame_obligations =~= pre.frame_obligations
172 }
173
174 pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
175 paddr: Paddr,
176 metadata: M,
177 as_unique: bool,
178 ptr: PPtr<MetaSlot>,
179 perm: simple_pptr::PointsTo<MetaSlot>,
180 ) -> bool {
181 &&& ptr.addr() == frame_to_meta(paddr)
182 &&& perm.addr() == frame_to_meta(paddr)
183 &&& perm.is_init()
184 &&& perm.pptr() == ptr
185 }
186
187 pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
188 rc_perm.value() >= REF_COUNT_MAX
189 }
190
191 pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
192 &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
193 &&& perm.addr() % META_SLOT_SIZE == 0
194 }
195
196 pub open spec fn get_from_in_use_success(
197 paddr: Paddr,
198 pre: MetaRegionOwners,
199 post: MetaRegionOwners,
200 ) -> bool
201 recommends
202 valid_frame_paddr(paddr),
203 pre.inv(),
204 {
205 let idx = frame_to_index(paddr);
206 let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
207 {
208 &&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
209 &&& post.slot_owners[idx].inner_perms.ref_count.id()
210 == pre.slot_owners[idx].inner_perms.ref_count.id()
211 &&& post.slot_owners[idx].inner_perms.storage
212 == pre.slot_owners[idx].inner_perms.storage
213 &&& post.slot_owners[idx].inner_perms.vtable_ptr
214 == pre.slot_owners[idx].inner_perms.vtable_ptr
215 &&& post.slot_owners[idx].inner_perms.in_list
216 == pre.slot_owners[idx].inner_perms.in_list
217 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
218 &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
219 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
220 &&& forall|i: int| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
221 }
222 }
223
224 pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
225 &&& (owner.inner_perms.ref_count.value() == 0 || owner.inner_perms.ref_count.value()
226 == REF_COUNT_UNIQUE)
227 &&& owner.inner_perms.storage.is_init()
228 &&& owner.inner_perms.in_list.value()
229 == 0
230 &&& owner.paths_in_pt.is_empty()
238 }
239
240 pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
241 recommends
242 pre.inv(),
243 pre.status == MetaSlotStatus::SHARED,
244 {
245 MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
246 }
247}
248
249impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
250 pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
251 Frame::<M> {
252 ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
253 _marker: PhantomData,
254 }
255 }
256}
257
258}