1use vstd::atomic::*;
2
3use vstd::prelude::*;
4use vstd::simple_pptr::{self, *};
5
6use core::ops::Range;
7
8use vstd_extra::cast_ptr::{self, Repr};
9use vstd_extra::drop_tracking::DropObligation;
10
11use vstd_extra::ownership::*;
12
13use super::meta_owners::{MetaPerm, MetaSlotModel, MetaSlotOwner, MetaSlotStorage};
14use super::*;
15use crate::mm::Paddr;
16use crate::mm::frame::Link;
17use crate::mm::frame::meta::{
18 AnyFrameMeta, META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, mapping::frame_to_meta,
19};
20use crate::mm::kspace::FRAME_METADATA_RANGE;
21use crate::specs::arch::{MAX_PADDR, PAGE_SIZE};
22
23use crate::specs::mm::frame::{
24 mapping::{frame_to_index, max_meta_slots, meta_addr},
25 meta_owners::Metadata,
26};
27
28verus! {
29
30#[verifier::ext_equal]
46pub tracked struct MetaRegionOwners {
47 pub slots: Map<usize, simple_pptr::PointsTo<MetaSlot>>,
48 pub slot_owners: Map<usize, MetaSlotOwner>,
49 pub frame_obligations: vstd::multiset::Multiset<usize>,
58}
59
60pub ghost struct MetaRegionModel {
61 pub slots: Map<usize, MetaSlotModel>,
62}
63
64impl Inv for MetaRegionOwners {
65 open spec fn inv(self) -> bool {
66 &&& {
67 forall|i: usize| i < max_meta_slots() <==> #[trigger] self.slot_owners.contains_key(i)
69 }
70 &&& {
71 forall|i: usize| #[trigger]
72 self.slot_owners.contains_key(i) ==> self.slots.contains_key(i)
73 }
74 &&& { forall|i: usize| #[trigger] self.slots.contains_key(i) ==> i < max_meta_slots() }
75 &&& {
76 forall|i: usize| #[trigger]
77 self.slots.contains_key(i) ==> {
78 &&& self.slot_owners[i].inv()
79 &&& self.slots[i].is_init()
80 &&& self.slots[i].addr() == meta_addr(i)
81 &&& self.slots[i].value().wf(self.slot_owners[i])
82 &&& self.slot_owners[i].slot_vaddr == self.slots[i].addr()
83 }
84 }
85 }
86}
87
88impl Inv for MetaRegionModel {
89 open spec fn inv(self) -> bool {
90 &&& forall|i: usize| i < max_meta_slots() <==> #[trigger] self.slots.contains_key(i)
91 &&& forall|i: usize| #[trigger] self.slots.contains_key(i) ==> self.slots[i].inv()
92 }
93}
94
95impl View for MetaRegionOwners {
96 type V = MetaRegionModel;
97
98 open spec fn view(&self) -> <Self as View>::V {
99 let slots = self.slot_owners.map_values(|s: MetaSlotOwner| s@);
100 MetaRegionModel { slots }
101 }
102}
103
104impl InvView for MetaRegionOwners {
105 proof fn view_preserves_inv(self) {
106 }
107}
108
109impl MetaRegionOwners {
110 pub open spec fn ref_count(self, i: usize) -> (res: u64)
111 recommends
112 self.inv(),
113 i < max_meta_slots() as usize,
114 {
115 self.slot_owners[i].inner_perms.ref_count.value()
116 }
117
118 pub open spec fn slot_owners_agree_except(self, other: MetaRegionOwners, idx: usize) -> bool {
121 forall|i: usize|
122 #![trigger other.slot_owners[i]]
123 i != idx ==> other.slot_owners[i] == self.slot_owners[i]
124 }
125
126 pub axiom fn borrow_typed_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
127 &self,
128 i: usize,
129 ) -> (tracked res: &vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<M>>)
130 requires
131 self.slots.contains_key(i),
132 self.slot_owners.contains_key(i),
133 vstd_extra::cast_ptr::PointsTo::<MetaSlot, Metadata<M>>::new_spec(
134 self.slots[i],
135 self.slot_owners[i].inner_perms,
136 ).wf(&self.slot_owners[i].inner_perms),
137 ensures
138 res.points_to == self.slots[i],
139 res.inner_perms == self.slot_owners[i].inner_perms,
140 res.wf(&res.inner_perms),
141 ;
142
143 pub axiom fn borrow_mut_typed_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
151 &mut self,
152 i: usize,
153 ) -> (tracked res: &mut vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<M>>)
154 requires
155 old(self).slots.contains_key(i),
156 old(self).slot_owners.contains_key(i),
157 vstd_extra::cast_ptr::PointsTo::<MetaSlot, Metadata<M>>::new_spec(
158 old(self).slots[i],
159 old(self).slot_owners[i].inner_perms,
160 ).wf(&old(self).slot_owners[i].inner_perms),
161 ensures
162 res.points_to == old(self).slots[i],
163 res.inner_perms == old(self).slot_owners[i].inner_perms,
164 res.wf(&res.inner_perms),
165 final(self).slots.dom() == old(self).slots.dom(),
166 final(self).slot_owners.dom() == old(self).slot_owners.dom(),
167 final(self).slots[i] == final(res).points_to,
168 final(self).slot_owners[i].inner_perms == final(res).inner_perms,
169 forall|k: usize| k != i ==> #[trigger] final(self).slots[k] == old(self).slots[k],
170 forall|k: usize|
171 k != i ==> #[trigger] final(self).slot_owners[k] == old(self).slot_owners[k],
172 final(self).slot_owners[i].usage == old(self).slot_owners[i].usage,
173 final(self).slot_owners[i].slot_vaddr == old(self).slot_owners[i].slot_vaddr,
174 final(self).slot_owners[i].paths_in_pt == old(self).slot_owners[i].paths_in_pt,
175 final(self).frame_obligations == old(self).frame_obligations,
176 ;
177
178 pub open spec fn paddr_range_in_region(self, range: Range<Paddr>) -> bool
179 recommends
180 self.inv(),
181 range.start < range.end < MAX_PADDR,
182 {
183 forall|paddr: Paddr|
184 #![trigger frame_to_index(paddr)]
185 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
186 ==> self.slots.contains_key(frame_to_index(paddr))
187 }
188
189 pub open spec fn paddr_range_not_mapped(self, range: Range<Paddr>) -> bool
190 recommends
191 self.inv(),
192 range.start < range.end < MAX_PADDR,
193 {
194 forall|paddr: Paddr|
195 #![trigger frame_to_index(paddr)]
196 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
197 ==> self.slot_owners[frame_to_index(paddr)].paths_in_pt.is_empty()
198 }
199
200 pub open spec fn paddr_range_not_in_region(self, range: Range<Paddr>) -> bool
201 recommends
202 self.inv(),
203 range.start < range.end < MAX_PADDR,
204 {
205 forall|paddr: Paddr|
206 #![trigger frame_to_index(paddr)]
207 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
208 ==> !self.slots.contains_key(frame_to_index(paddr))
209 }
210
211 pub proof fn paddr_not_mapped_at(self, range: Range<Paddr>, paddr: Paddr)
213 requires
214 self.paddr_range_not_mapped(range),
215 range.start <= paddr,
216 paddr < range.end,
217 paddr % PAGE_SIZE == 0,
218 ensures
219 self.slot_owners[frame_to_index(paddr)].paths_in_pt.is_empty(),
220 {
221 }
224
225 pub proof fn inv_implies_correct_addr(self, paddr: usize)
226 requires
227 paddr < MAX_PADDR,
228 paddr % PAGE_SIZE == 0,
229 self.inv(),
230 ensures
231 self.slot_owners.contains_key(frame_to_index(paddr) as usize),
232 {
233 }
234
235 pub axiom fn sync_slot_perm(
240 tracked &mut self,
241 index: usize,
242 perm: &simple_pptr::PointsTo<MetaSlot>,
243 )
244 ensures
245 final(self).slots == old(self).slots.insert(index, *perm),
246 final(self).slot_owners == old(self).slot_owners,
247 final(self).frame_obligations == old(self).frame_obligations,
248 ;
249
250 pub open spec fn clean_inv(self) -> bool {
263 &&& self.inv()
264 &&& self.frame_obligations.len() == 0
268 }
269
270 pub open spec fn mint_frame_obligation(self, slot_idx: usize) -> Self {
274 Self { frame_obligations: self.frame_obligations.insert(slot_idx), ..self }
275 }
276
277 pub open spec fn redeem_frame_obligation(self, slot_idx: usize) -> Self
278 recommends
279 self.frame_obligations.count(slot_idx) > 0,
280 {
281 Self { frame_obligations: self.frame_obligations.remove(slot_idx), ..self }
282 }
283
284 pub axiom fn tracked_mint_frame_obligation(tracked &mut self, slot_idx: usize) -> (tracked obl:
289 DropObligation<usize>)
290 ensures
291 obl.value() == slot_idx,
292 *final(self) == old(self).mint_frame_obligation(slot_idx),
293 ;
294
295 pub axiom fn tracked_redeem_frame_obligation(
299 tracked &mut self,
300 tracked obl: DropObligation<usize>,
301 )
302 requires
303 old(self).frame_obligations.count(obl.value()) > 0,
304 ensures
305 *final(self) == old(self).redeem_frame_obligation(obl.value()),
306 ;
307}
308
309}