ostd/specs/mm/frame/
meta_specs.rs1use vstd::atomic::*;
2use vstd::atomic::*;
3
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 META_SLOT_SIZE, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
15 mapping::{frame_to_meta, meta_to_frame},
16};
17use crate::mm::frame::*;
18use crate::mm::kspace::FRAME_METADATA_RANGE;
19use crate::mm::{Paddr, PagingLevel, Vaddr};
20use crate::specs::arch::*;
21use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
22use crate::specs::mm::frame::{
23 mapping::{frame_to_index, index_to_frame, lemma_paddr_to_meta_biinjective, meta_addr},
24 meta_owners::MetadataInnerPerms,
25};
26
27use core::marker::PhantomData;
28
29verus! {
30
31global layout MetaSlot is size == 64, align == 8;
32
33impl MetaSlot {
34 pub proof fn lemma_layout()
35 ensures
36 core::mem::size_of::<MetaSlot>() == META_SLOT_SIZE,
37 vstd::layout::size_of::<MetaSlot>() == META_SLOT_SIZE,
38 {
39 broadcast use VERUS_layout_of_MetaSlot;
40
41 }
42
43 #[verus_spec(res =>
45 with
46 Tracked(perm): Tracked<&vstd::simple_pptr::PointsTo<MetaSlot>>,
47 requires
48 perm.value() == self,
49 addr == perm.addr(),
50 ensures
51 res.ptr.addr() == addr,
52 res.addr() == addr,
53 )]
54 pub fn cast_slot<M: AnyFrameMeta + Repr<MetaSlotStorage>>(&self, addr: usize) -> ReprPtr<
55 MetaSlot,
56 Metadata<M>,
57 > {
58 ReprPtr::<MetaSlot, Metadata<M>> { ptr: PPtr::from_addr(addr), _T: PhantomData }
59 }
60
61 pub open spec fn get_from_unused_inner_perms_spec(
62 as_unique: bool,
63 perms: MetadataInnerPerms,
64 ) -> bool {
65 &&& perms.ref_count.value() == (if as_unique {
66 REF_COUNT_UNIQUE as u64
67 } else {
68 1u64
69 })
70 &&& perms.in_list.value() == 0
71 &&& perms.storage.is_init()
72 &&& perms.vtable_ptr.is_init()
73 }
74
75 pub open spec fn get_from_unused_spec(
81 paddr: Paddr,
82 as_unique: bool,
83 pre: MetaRegionOwners,
84 post: MetaRegionOwners,
85 ) -> bool
86 recommends
87 paddr % PAGE_SIZE == 0,
88 paddr < MAX_PADDR,
89 pre.inv(),
90 {
91 let idx = frame_to_index(paddr);
92 {
93 &&& post.slot_owners.dom() =~= pre.slot_owners.dom()
94 &&& MetaSlot::get_from_unused_inner_perms_spec(
95 as_unique,
96 post.slot_owners[idx].inner_perms,
97 )
98 &&& post.slot_owners[idx].usage == PageUsage::Frame
99 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
100 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
101 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
102 &&& pre.slot_owners[idx].inner_perms.ref_count.value()
103 == REF_COUNT_UNUSED
104 }
108 }
109
110 pub open spec fn get_node_from_unused_spec(
118 paddr: Paddr,
119 pre: MetaRegionOwners,
120 post: MetaRegionOwners,
121 ) -> bool
122 recommends
123 paddr % PAGE_SIZE == 0,
124 paddr < MAX_PADDR,
125 pre.inv(),
126 {
127 let idx = frame_to_index(paddr);
128 {
129 &&& post.slot_owners.dom() =~= pre.slot_owners.dom()
130 &&& MetaSlot::get_from_unused_inner_perms_spec(false, post.slot_owners[idx].inner_perms)
131 &&& post.slot_owners[idx].usage == PageUsage::PageTable
132 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
133 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
134 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
135 &&& pre.slot_owners[idx].inner_perms.ref_count.value() == REF_COUNT_UNUSED
136 }
137 }
138
139 pub open spec fn slot_perm_extracted_spec(
143 paddr: Paddr,
144 pre: MetaRegionOwners,
145 post: MetaRegionOwners,
146 ) -> bool {
147 post.slots =~= pre.slots.remove(frame_to_index(paddr))
148 }
149
150 pub open spec fn slot_perm_reparked_spec(
157 paddr: Paddr,
158 pre: MetaRegionOwners,
159 post: MetaRegionOwners,
160 ) -> bool {
161 let idx = frame_to_index(paddr);
162 &&& post.slots.dom() =~= pre.slots.dom()
163 &&& forall|k: usize|
164 #![trigger post.slots[k]]
165 k != idx && pre.slots.contains_key(k) ==> post.slots[k] == pre.slots[k]
166 }
167
168 pub open spec fn live_frame_obligations_ok_spec(
174 paddr: Paddr,
175 pre: MetaRegionOwners,
176 post: MetaRegionOwners,
177 ) -> bool {
178 &&& post.frame_obligations =~= pre.frame_obligations.insert(frame_to_index(paddr))
179 }
180
181 pub open spec fn live_frame_obligations_err_spec(
184 pre: MetaRegionOwners,
185 post: MetaRegionOwners,
186 ) -> bool {
187 &&& post.frame_obligations =~= pre.frame_obligations
188 }
189
190 pub open spec fn get_from_unused_perm_spec<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
191 paddr: Paddr,
192 metadata: M,
193 as_unique: bool,
194 ptr: PPtr<MetaSlot>,
195 perm: simple_pptr::PointsTo<MetaSlot>,
196 ) -> bool {
197 &&& ptr.addr() == frame_to_meta(paddr)
198 &&& perm.addr() == frame_to_meta(paddr)
199 &&& perm.is_init()
200 &&& perm.pptr() == ptr
201 }
202
203 pub open spec fn inc_ref_count_panic_cond(rc_perm: PermissionU64) -> bool {
204 rc_perm.value() >= REF_COUNT_MAX
205 }
206
207 pub open spec fn frame_paddr_safety_cond(perm: vstd::simple_pptr::PointsTo<MetaSlot>) -> bool {
208 &&& FRAME_METADATA_RANGE.start <= perm.addr() < FRAME_METADATA_RANGE.end
209 &&& perm.addr() % META_SLOT_SIZE == 0
210 }
211
212 pub open spec fn get_from_in_use_success(
213 paddr: Paddr,
214 pre: MetaRegionOwners,
215 post: MetaRegionOwners,
216 ) -> bool
217 recommends
218 paddr % PAGE_SIZE == 0,
219 paddr < MAX_PADDR,
220 pre.inv(),
221 {
222 let idx = frame_to_index(paddr);
223 let pre_perms = pre.slot_owners[idx].inner_perms.ref_count.value();
224 {
225 &&& post.slot_owners[idx].inner_perms.ref_count.value() == pre_perms + 1
226 &&& post.slot_owners[idx].inner_perms.ref_count.id()
227 == pre.slot_owners[idx].inner_perms.ref_count.id()
228 &&& post.slot_owners[idx].inner_perms.storage
229 == pre.slot_owners[idx].inner_perms.storage
230 &&& post.slot_owners[idx].inner_perms.vtable_ptr
231 == pre.slot_owners[idx].inner_perms.vtable_ptr
232 &&& post.slot_owners[idx].inner_perms.in_list
233 == pre.slot_owners[idx].inner_perms.in_list
234 &&& post.slot_owners[idx].slot_vaddr == pre.slot_owners[idx].slot_vaddr
235 &&& post.slot_owners[idx].usage == pre.slot_owners[idx].usage
236 &&& post.slot_owners[idx].paths_in_pt == pre.slot_owners[idx].paths_in_pt
237 &&& forall|i: usize| i != idx ==> (#[trigger] post.slot_owners[i] == pre.slot_owners[i])
238 }
239 }
240
241 pub open spec fn drop_last_in_place_safety_cond(owner: MetaSlotOwner) -> bool {
242 &&& (owner.inner_perms.ref_count.value() == 0 || owner.inner_perms.ref_count.value()
243 == REF_COUNT_UNIQUE)
244 &&& owner.inner_perms.storage.is_init()
245 &&& owner.inner_perms.in_list.value()
246 == 0
247 &&& owner.paths_in_pt.is_empty()
255 }
256
257 pub open spec fn inc_ref_count_spec(&self, pre: MetaSlotModel) -> (MetaSlotModel)
258 recommends
259 pre.inv(),
260 pre.status == MetaSlotStatus::SHARED,
261 {
262 MetaSlotModel { ref_count: (pre.ref_count + 1) as u64, ..pre }
263 }
264}
265
266impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
267 pub open spec fn from_raw_spec(paddr: Paddr) -> Self {
268 Frame::<M> {
269 ptr: PPtr::<MetaSlot>(frame_to_meta(paddr), PhantomData),
270 _marker: PhantomData,
271 }
272 }
273}
274
275pub broadcast proof fn lemma_meta_addr_to_index(i: usize)
282 requires
283 i < MAX_NR_PAGES,
284 ensures
285 #[trigger] frame_to_index(meta_to_frame(meta_addr(i))) == i,
286{
287 let p = index_to_frame(i);
288
289 lemma_paddr_to_meta_biinjective(p);
292}
293
294}