ostd/specs/mm/frame/
frame_specs.rs1use core::marker::PhantomData;
2
3use vstd::prelude::*;
4use vstd_extra::{cast_ptr::*, drop_tracking::*, ownership::*};
5
6use crate::specs::{
7 arch::*,
8 mm::frame::{
9 mapping::{frame_to_index, meta_to_index},
10 meta_owners::PageUsage,
11 meta_region_owners::MetaRegionOwners,
12 },
13};
14
15use crate::mm::{
16 Paddr, PagingLevel, Vaddr,
17 frame::{
18 meta::{
19 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
20 mapping::{frame_to_meta, meta_to_frame},
21 },
22 *,
23 },
24 kspace::FRAME_METADATA_RANGE,
25};
26
27verus! {
28
29impl<'a, M: ?Sized> Frame<M> {
33 pub open spec fn from_raw_requires_safety(regions: MetaRegionOwners, paddr: Paddr) -> bool {
36 &&& regions.contains(frame_to_index(paddr))
37 &&& regions.slot_owner(paddr).slot_vaddr == frame_to_meta(paddr)
38 &&& valid_frame_paddr(paddr)
39 &&& regions.inv()
40 &&& regions.slot_owner(paddr).ref_count() != REF_COUNT_UNUSED
41 }
42
43 pub open spec fn from_raw_ensures(
44 old_regions: MetaRegionOwners,
45 new_regions: MetaRegionOwners,
46 paddr: Paddr,
47 r: Self,
48 ) -> bool {
49 &&& new_regions.inv()
50 &&& new_regions.contains(frame_to_index(paddr))
51 &&& new_regions.slot_owner(paddr) =~= old_regions.slot_owner(paddr)
52 &&& new_regions.slot_owner(paddr).slot_vaddr == r.ptr.addr()
53 &&& forall|i: int|
54 #![trigger new_regions.slot_owners[i], old_regions.slot_owners[i]]
55 i != frame_to_index(paddr) ==> new_regions.slot_owners[i] == old_regions.slot_owners[i]
56 &&& forall|i: int|
57 i != frame_to_index(paddr) ==> new_regions.contains(i) == old_regions.contains(i)
58 &&& r.ptr.addr() == frame_to_meta(paddr)
59 &&& r.start_paddr_spec() == paddr
60 &&& r.inv()
61 &&& new_regions.frame_obligations =~= old_regions.frame_obligations.insert(
68 frame_to_index(paddr),
69 )
70 }
71
72 pub open spec fn into_raw_post_noninterference(
74 self,
75 old_regions: MetaRegionOwners,
76 new_regions: MetaRegionOwners,
77 ) -> bool {
78 &&& forall|i: int|
79 #![trigger new_regions.slots[i], old_regions.slots[i]]
80 i != self.index() && old_regions.contains(i) ==> new_regions.contains(i)
81 && new_regions.slots[i] == old_regions.slots[i]
82 &&& forall|i: int|
83 #![trigger new_regions.slot_owners[i], old_regions.slot_owners[i]]
84 i != self.index() ==> new_regions.slot_owners[i] == old_regions.slot_owners[i]
85 &&& new_regions.slot_owners.dom() =~= old_regions.slot_owners.dom()
86 }
87}
88
89impl<M: ?Sized> Inv for Frame<M> {
90 open spec fn inv(self) -> bool {
91 &&& self.ptr.addr() % META_SLOT_SIZE == 0
92 &&& FRAME_METADATA_RANGE.start <= self.ptr.addr() < FRAME_METADATA_RANGE.start
93 + MAX_NR_PAGES * META_SLOT_SIZE
94 }
95}
96
97impl<M: ?Sized> Frame<M> {
98 pub open spec fn index(self) -> int {
99 frame_to_index(self.start_paddr_spec())
100 }
101
102 pub open spec fn start_paddr_spec(self) -> Paddr {
103 meta_to_frame(self.ptr.addr())
104 }
105
106 pub open spec fn from_unused_spec(
107 paddr: Paddr,
108 pre: MetaRegionOwners,
109 post: MetaRegionOwners,
110 ) -> bool {
111 let idx = frame_to_index(paddr);
112 let pre_owner = pre.slot_owners[idx];
113 let post_owner = post.slot_owners[idx];
114 {
115 &&& pre_owner.ref_count() == REF_COUNT_UNUSED
116 &&& MetaSlot::get_from_unused_owner_spec(false, post_owner)
117 &&& post_owner.usage is Frame
118 &&& post_owner.slot_vaddr == pre_owner.slot_vaddr
119 &&& post_owner.paths_in_pt == pre_owner.paths_in_pt
120 &&& post =~= pre.insert_slot_owner(paddr, post_owner).mint_frame_obligation(idx)
121 }
122 }
123}
124
125impl<M: ?Sized> Frame<M> {
126 pub open spec fn wf_with_region(self, s: MetaRegionOwners) -> bool {
151 let idx = self.index();
152 let slot_own = s.slot_owners[idx];
153 &&& self.inv()
154 &&& s.inv()
155 &&& s.contains(idx)
156 &&& s.slots[idx].pptr() == self.ptr
157 &&& slot_own.ref_count() != REF_COUNT_UNUSED
158 &&& slot_own.ref_count() != REF_COUNT_UNIQUE
159 &&& slot_own.ref_count() > 0
160 &&& slot_own.ref_count() <= REF_COUNT_MAX
161 }
162}
163
164impl<M: ?Sized> TrackDrop for Frame<M> {
171 type State = MetaRegionOwners;
172
173 type Obligation = DropObligation<int>;
180
181 open spec fn tracked_redeem_requires(self, s: Self::State) -> bool {
182 &&& s.contains(self.index())
183 &&& s.inv()
184 }
185
186 open spec fn tracked_redeem_ensures(
187 self,
188 s0: Self::State,
189 s1: Self::State,
190 obl: Self::Obligation,
191 ) -> bool {
192 let slot_own = s0.slot_owners[self.index()];
193 &&& s1.slot_owners[self.index()] == slot_own
194 &&& forall|i: int|
195 #![trigger s1.slot_owners[i]]
196 i != self.index() ==> s1.slot_owners[i] == s0.slot_owners[i]
197 &&& s1.slots =~= s0.slots
198 &&& s1.slot_owners.dom()
199 =~= s0.slot_owners.dom()
200 &&& s1.frame_obligations =~= s0.frame_obligations.insert(self.index())
205 &&& obl.value() == self.index()
206 }
207
208 proof fn tracked_redeem(self, tracked s: &mut Self::State) -> (tracked obl: Self::Obligation) {
209 let meta_addr = self.ptr.addr();
210 let index = meta_to_index(meta_addr);
211 let tracked mut slot_own = s.slot_owners.tracked_remove(index);
212 s.slot_owners.tracked_insert(index, slot_own);
213 s.tracked_mint_frame_obligation(index)
217 }
218
219 open spec fn drop_requires(self, s: Self::State, obl: Self::Obligation) -> bool {
223 let idx = self.index();
224 let slot_own = s.slot_owners[idx];
225 &&& self.wf_with_region(s)
230 &&& slot_own.ref_count() == 1 ==> {
231 &&& slot_own.paths_in_pt.is_empty()
232 }
233 &&& s.frame_obligations.count(self.index()) > 0
234 &&& obl.value() == self.index()
235 }
236
237 open spec fn drop_ensures(
238 self,
239 s0: Self::State,
240 s1: Self::State,
241 obl: Self::Obligation,
242 ) -> bool {
243 let idx = self.index();
244 let so0 = s0.slot_owners[idx];
245 let so1 = s1.slot_owners[idx];
246 &&& s1.inv()
247 &&& forall|i: int|
248 #![trigger s1.slot_owners[i]]
249 i != idx ==> s1.slot_owners[i] == s0.slot_owners[i]
250 &&& s1.slots =~= s0.slots
251 &&& s1.slot_owners.dom()
252 =~= s0.slot_owners.dom()
253 &&& so1.slot_vaddr == so0.slot_vaddr
256 &&& so1.usage == so0.usage
257 &&& so1.paths_in_pt == so0.paths_in_pt
258 &&& so0.ref_count() == 1 ==> so1.ref_count() == REF_COUNT_UNUSED
259 &&& so0.ref_count() > 1 ==> so1.ref_count() == (so0.ref_count()
260 - 1) as u64
261 &&& s1.frame_obligations =~= s0.frame_obligations.remove(self.index())
267 }
268}
269
270}