1use core::ops::Range;
2
3use vstd::prelude::*;
4
5use vstd::{
6 atomic::*,
7 simple_pptr::{self, *},
8};
9use vstd_extra::{
10 cast_ptr::{self, Repr},
11 drop_tracking::DropObligation,
12 ownership::*,
13};
14
15use crate::specs::arch::valid_frame_paddr;
16use crate::specs::{
17 arch::{MAX_PADDR, PAGE_SIZE},
18 mm::frame::{
19 mapping::{frame_to_index, index_to_meta, max_meta_slots},
20 meta_owners::Metadata,
21 },
22};
23
24use crate::mm::{
25 Paddr,
26 frame::{
27 Link,
28 meta::{AnyFrameMeta, META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, mapping::frame_to_meta},
29 },
30 kspace::FRAME_METADATA_RANGE,
31};
32
33use super::{
34 meta_owners::{MetaPerm, MetaSlotModel, MetaSlotOwner, MetaSlotStorage},
35 *,
36};
37
38verus! {
39
40#[verifier::ext_equal]
56pub tracked struct MetaRegionOwners {
57 pub slots: Map<int, simple_pptr::PointsTo<MetaSlot>>,
58 pub slot_owners: Map<int, MetaSlotOwner>,
59 pub frame_obligations: vstd::multiset::Multiset<int>,
68}
69
70pub ghost struct MetaRegionModel {
71 pub slots: Map<int, MetaSlotModel>,
72}
73
74impl Inv for MetaRegionOwners {
75 open spec fn inv(self) -> bool {
76 &&& {
77 forall|i: int|
79 0 <= i < max_meta_slots() <==> #[trigger] self.slot_owners.contains_key(i)
80 }
81 &&& {
82 forall|i: int| #[trigger]
83 self.slot_owners.contains_key(i) ==> self.slots.contains_key(i)
84 }
85 &&& { forall|i: int| #[trigger] self.slots.contains_key(i) ==> 0 <= i < max_meta_slots() }
86 &&& {
87 forall|i: int| #[trigger]
88 self.slots.contains_key(i) ==> {
89 &&& self.slot_owners[i].inv()
90 &&& self.slots[i].is_init()
91 &&& self.slots[i].addr() == index_to_meta(i)
92 &&& self.slots[i].value().wf(self.slot_owners[i])
93 &&& self.slot_owners[i].slot_vaddr == self.slots[i].addr()
94 }
95 }
96 }
97}
98
99impl Inv for MetaRegionModel {
100 open spec fn inv(self) -> bool {
101 &&& forall|i: int| 0 <= i < max_meta_slots() <==> #[trigger] self.slots.contains_key(i)
102 &&& forall|i: int| #[trigger] self.slots.contains_key(i) ==> self.slots[i].inv()
103 }
104}
105
106impl View for MetaRegionOwners {
107 type V = MetaRegionModel;
108
109 open spec fn view(&self) -> <Self as View>::V {
110 let slots = self.slot_owners.map_values(|s: MetaSlotOwner| s@);
111 MetaRegionModel { slots }
112 }
113}
114
115impl InvView for MetaRegionOwners {
116 proof fn view_preserves_inv(self) {
117 }
118}
119
120impl MetaRegionOwners {
121 pub open spec fn insert_slot_owner(self, paddr: Paddr, owner: MetaSlotOwner) -> Self {
122 let index = frame_to_index(paddr);
123 Self { slot_owners: self.slot_owners.insert(index, owner), ..self }
124 }
125
126 pub open spec fn ref_count(self, i: int) -> (res: u64)
127 recommends
128 self.inv(),
129 0 <= i < max_meta_slots(),
130 {
131 self.slot_owners[i].inner_perms.ref_count.value()
132 }
133
134 pub open spec fn slot_owners_agree_except(self, other: MetaRegionOwners, idx: int) -> bool {
137 forall|i: int|
138 #![trigger other.slot_owners[i]]
139 i != idx ==> other.slot_owners[i] == self.slot_owners[i]
140 }
141
142 pub axiom fn borrow_typed_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
143 &self,
144 i: int,
145 ) -> (tracked res: &vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<M>>)
146 requires
147 self.slots.contains_key(i),
148 self.slot_owners.contains_key(i),
149 vstd_extra::cast_ptr::PointsTo::<MetaSlot, Metadata<M>>::new_spec(
150 self.slots[i],
151 self.slot_owners[i].inner_perms,
152 ).wf(&self.slot_owners[i].inner_perms),
153 ensures
154 res.points_to == self.slots[i],
155 res.inner_perms == self.slot_owners[i].inner_perms,
156 res.wf(&res.inner_perms),
157 ;
158
159 pub axiom fn borrow_mut_typed_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
167 &mut self,
168 i: int,
169 ) -> (tracked res: &mut vstd_extra::cast_ptr::PointsTo<MetaSlot, Metadata<M>>)
170 requires
171 old(self).slots.contains_key(i),
172 old(self).slot_owners.contains_key(i),
173 vstd_extra::cast_ptr::PointsTo::<MetaSlot, Metadata<M>>::new_spec(
174 old(self).slots[i],
175 old(self).slot_owners[i].inner_perms,
176 ).wf(&old(self).slot_owners[i].inner_perms),
177 ensures
178 res.points_to == old(self).slots[i],
179 res.inner_perms == old(self).slot_owners[i].inner_perms,
180 res.wf(&res.inner_perms),
181 final(self).slots.dom() == old(self).slots.dom(),
182 final(self).slot_owners.dom() == old(self).slot_owners.dom(),
183 final(self).slots[i] == final(res).points_to,
184 final(self).slot_owners[i].inner_perms == final(res).inner_perms,
185 forall|k: int| k != i ==> #[trigger] final(self).slots[k] == old(self).slots[k],
186 forall|k: int|
187 k != i ==> #[trigger] final(self).slot_owners[k] == old(self).slot_owners[k],
188 final(self).slot_owners[i].usage == old(self).slot_owners[i].usage,
189 final(self).slot_owners[i].slot_vaddr == old(self).slot_owners[i].slot_vaddr,
190 final(self).slot_owners[i].paths_in_pt == old(self).slot_owners[i].paths_in_pt,
191 final(self).frame_obligations == old(self).frame_obligations,
192 ;
193
194 pub open spec fn paddr_range_in_region(self, range: Range<Paddr>) -> bool
195 recommends
196 self.inv(),
197 range.start < range.end < MAX_PADDR,
198 {
199 forall|paddr: Paddr|
200 #![trigger frame_to_index(paddr)]
201 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
202 ==> self.slots.contains_key(frame_to_index(paddr))
203 }
204
205 pub open spec fn paddr_range_not_mapped(self, range: Range<Paddr>) -> bool
206 recommends
207 self.inv(),
208 range.start < range.end < MAX_PADDR,
209 {
210 forall|paddr: Paddr|
211 #![trigger frame_to_index(paddr)]
212 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
213 ==> self.slot_owners[frame_to_index(paddr)].paths_in_pt.is_empty()
214 }
215
216 pub open spec fn paddr_range_not_in_region(self, range: Range<Paddr>) -> bool
217 recommends
218 self.inv(),
219 range.start < range.end < MAX_PADDR,
220 {
221 forall|paddr: Paddr|
222 #![trigger frame_to_index(paddr)]
223 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
224 ==> !self.slots.contains_key(frame_to_index(paddr))
225 }
226
227 pub proof fn paddr_not_mapped_at(self, range: Range<Paddr>, paddr: Paddr)
229 requires
230 self.paddr_range_not_mapped(range),
231 range.start <= paddr,
232 paddr < range.end,
233 paddr % PAGE_SIZE == 0,
234 ensures
235 self.slot_owners[frame_to_index(paddr)].paths_in_pt.is_empty(),
236 {
237 }
240
241 pub proof fn inv_implies_correct_addr(self, paddr: usize)
242 requires
243 valid_frame_paddr(paddr),
244 self.inv(),
245 ensures
246 self.slot_owners.contains_key(frame_to_index(paddr)),
247 {
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: int) -> 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: int) -> 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: int) -> (tracked obl:
289 DropObligation<int>)
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<int>,
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}