1use core::ops::Range;
2
3use vstd::prelude::*;
4
5use vstd::{
6 atomic::*,
7 simple_pptr::{self, *},
8};
9use vstd_extra::{cast_ptr::Repr, drop_tracking::DropObligation, ownership::*};
10
11use crate::specs::arch::valid_frame_paddr;
12use crate::specs::{
13 arch::{MAX_PADDR, PAGE_SIZE},
14 mm::frame::mapping::{frame_to_index, index_to_meta, max_meta_slots},
15};
16
17use crate::mm::{
18 Paddr,
19 frame::{
20 Link,
21 meta::{AnyFrameMeta, META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, mapping::frame_to_meta},
22 },
23 kspace::FRAME_METADATA_RANGE,
24};
25
26use super::{
27 meta_owners::{MetaSlotModel, MetaSlotOwner},
28 *,
29};
30
31verus! {
32
33#[verifier::ext_equal]
49pub tracked struct MetaRegionOwners {
50 pub slots: Map<int, &'static simple_pptr::PointsTo<MetaSlot>>,
51 pub slot_owners: Map<int, MetaSlotOwner>,
52 pub frame_obligations: vstd::multiset::Multiset<int>,
61}
62
63pub ghost struct MetaRegionModel {
64 pub slots: Map<int, MetaSlotModel>,
65}
66
67impl Inv for MetaRegionOwners {
68 open spec fn inv(self) -> bool {
69 &&& {
70 forall|i: int|
73 0 <= i < max_meta_slots() <==> #[trigger] self.slot_owners.contains_key(i)
74 }
75 &&& {
76 forall|i: int| #[trigger]
77 self.slot_owners.contains_key(i) ==> self.slots.contains_key(i)
78 }
79 &&& { forall|i: int| #[trigger] self.slots.contains_key(i) ==> 0 <= i < max_meta_slots() }
80 &&& {
81 forall|i: int| #[trigger]
82 self.slots.contains_key(i) ==> {
83 &&& self.slot_owners[i].inv()
84 &&& self.slots[i].is_init()
85 &&& self.slots[i].addr() == index_to_meta(i)
86 &&& self.slots[i].value().wf(self.slot_owners[i])
87 &&& self.slot_owners[i].slot_vaddr == self.slots[i].addr()
88 }
89 }
90 }
91}
92
93impl MetaRegionModel {
94 pub open spec fn contains(self, index: int) -> bool {
95 self.slots.contains_key(index)
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 contains(self, index: int) -> bool {
123 &&& self.slot_owners.contains_key(index)
124 &&& self.slots.contains_key(index)
125 }
126
127 pub open spec fn insert_slot_owner(self, paddr: Paddr, owner: MetaSlotOwner) -> Self {
128 let index = frame_to_index(paddr);
129 Self { slot_owners: self.slot_owners.insert(index, owner), ..self }
130 }
131
132 pub open spec fn ref_count(self, i: int) -> (res: u64)
133 recommends
134 0 <= i < max_meta_slots(),
135 {
136 self.slot_owners[i].ref_count()
137 }
138
139 pub open spec fn slot_owners_agree_except(self, other: MetaRegionOwners, idx: int) -> bool {
142 forall|i: int|
143 #![trigger other.slot_owners[i]]
144 i != idx ==> other.slot_owners[i] == self.slot_owners[i]
145 }
146
147 pub open spec fn paddr_range_in_region(self, range: Range<Paddr>) -> bool
148 recommends
149 range.start < range.end < MAX_PADDR,
150 {
151 forall|paddr: Paddr|
152 #![trigger frame_to_index(paddr)]
153 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> self.contains(
154 frame_to_index(paddr),
155 )
156 }
157
158 pub open spec fn paddr_range_not_mapped(self, range: Range<Paddr>) -> bool
159 recommends
160 range.start < range.end < MAX_PADDR,
161 {
162 forall|paddr: Paddr|
163 #![trigger frame_to_index(paddr)]
164 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> self.slot_owner(
165 paddr,
166 ).paths_in_pt.is_empty()
167 }
168
169 pub open spec fn paddr_range_not_in_region(self, range: Range<Paddr>) -> bool
170 recommends
171 range.start < range.end < MAX_PADDR,
172 {
173 forall|paddr: Paddr|
174 #![trigger frame_to_index(paddr)]
175 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0) ==> !self.contains(
176 frame_to_index(paddr),
177 )
178 }
179
180 pub proof fn paddr_not_mapped_at(self, range: Range<Paddr>, paddr: Paddr)
182 requires
183 self.paddr_range_not_mapped(range),
184 range.start <= paddr,
185 paddr < range.end,
186 paddr % PAGE_SIZE == 0,
187 ensures
188 self.slot_owner(paddr).paths_in_pt.is_empty(),
189 {
190 }
191
192 pub proof fn lemma_contains_valid_frame_paddr(self, paddr: usize)
193 requires
194 valid_frame_paddr(paddr),
195 self.inv(),
196 ensures
197 self.contains(frame_to_index(paddr)),
198 {
199 }
200
201 pub open spec fn slot_owner(self, paddr: Paddr) -> MetaSlotOwner {
203 self.slot_owners[frame_to_index(paddr)]
204 }
205
206 pub proof fn tracked_borrow_slot(tracked &self, paddr: Paddr) -> (tracked ret:
208 &'static simple_pptr::PointsTo<MetaSlot>)
209 requires
210 valid_frame_paddr(paddr),
211 self.inv(),
212 returns
213 self.slots[frame_to_index(paddr)],
214 {
215 self.lemma_contains_valid_frame_paddr(paddr);
216 *self.slots.tracked_borrow(frame_to_index(paddr))
217 }
218
219 pub proof fn tracked_borrow_slot_owner(tracked &self, paddr: Paddr) -> (tracked ret:
221 &MetaSlotOwner)
222 requires
223 valid_frame_paddr(paddr),
224 self.inv(),
225 returns
226 self.slot_owner(paddr),
227 {
228 self.lemma_contains_valid_frame_paddr(paddr);
229 self.slot_owners.tracked_borrow(frame_to_index(paddr))
230 }
231
232 pub proof fn tracked_borrow_mut_slot_owner(tracked &mut self, paddr: Paddr) -> (tracked ret:
234 &mut MetaSlotOwner)
235 requires
236 valid_frame_paddr(paddr),
237 self.inv(),
238 ensures
239 *ret == old(self).slot_owner(paddr),
240 *final(self) == (Self {
241 slot_owners: old(self).slot_owners.insert(frame_to_index(paddr), *final(ret)),
242 ..*old(self)
243 }),
244 {
245 self.lemma_contains_valid_frame_paddr(paddr);
246 self.slot_owners.tracked_borrow_mut(frame_to_index(paddr))
247 }
248
249 pub open spec fn clean_inv(self) -> bool {
262 &&& self.inv()
263 &&& self.frame_obligations.len() == 0
267 }
268
269 pub open spec fn mint_frame_obligation(self, slot_idx: int) -> Self {
273 Self { frame_obligations: self.frame_obligations.insert(slot_idx), ..self }
274 }
275
276 pub open spec fn redeem_frame_obligation(self, slot_idx: int) -> Self
277 recommends
278 self.frame_obligations.count(slot_idx) > 0,
279 {
280 Self { frame_obligations: self.frame_obligations.remove(slot_idx), ..self }
281 }
282
283 pub axiom fn tracked_mint_frame_obligation(tracked &mut self, slot_idx: int) -> (tracked obl:
288 DropObligation<int>)
289 ensures
290 obl.value() == slot_idx,
291 *final(self) == old(self).mint_frame_obligation(slot_idx),
292 ;
293
294 pub axiom fn tracked_redeem_frame_obligation(
298 tracked &mut self,
299 tracked obl: DropObligation<int>,
300 )
301 requires
302 old(self).frame_obligations.count(obl.value()) > 0,
303 ensures
304 *final(self) == old(self).redeem_frame_obligation(obl.value()),
305 ;
306}
307
308}