ostd/specs/mm/frame/
meta_region_owners.rs1use 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_not_mapped(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.slot_owner(
154 paddr,
155 ).paths_in_pt.is_empty()
156 }
157
158 pub proof fn paddr_not_mapped_at(self, range: Range<Paddr>, paddr: Paddr)
160 requires
161 self.paddr_range_not_mapped(range),
162 range.start <= paddr,
163 paddr < range.end,
164 paddr % PAGE_SIZE == 0,
165 ensures
166 self.slot_owner(paddr).paths_in_pt.is_empty(),
167 {
168 }
169
170 pub proof fn lemma_contains_valid_frame_paddr(self, paddr: usize)
171 requires
172 valid_frame_paddr(paddr),
173 self.inv(),
174 ensures
175 self.contains(frame_to_index(paddr)),
176 {
177 }
178
179 pub open spec fn slot_owner(self, paddr: Paddr) -> MetaSlotOwner {
181 self.slot_owners[frame_to_index(paddr)]
182 }
183
184 pub proof fn tracked_borrow_slot(tracked &self, paddr: Paddr) -> (tracked ret:
186 &'static simple_pptr::PointsTo<MetaSlot>)
187 requires
188 valid_frame_paddr(paddr),
189 self.inv(),
190 returns
191 self.slots[frame_to_index(paddr)],
192 {
193 self.lemma_contains_valid_frame_paddr(paddr);
194 *self.slots.tracked_borrow(frame_to_index(paddr))
195 }
196
197 pub proof fn tracked_borrow_slot_owner(tracked &self, paddr: Paddr) -> (tracked ret:
199 &MetaSlotOwner)
200 requires
201 valid_frame_paddr(paddr),
202 self.inv(),
203 returns
204 self.slot_owner(paddr),
205 {
206 self.lemma_contains_valid_frame_paddr(paddr);
207 self.slot_owners.tracked_borrow(frame_to_index(paddr))
208 }
209
210 pub proof fn tracked_borrow_mut_slot_owner(tracked &mut self, paddr: Paddr) -> (tracked ret:
212 &mut MetaSlotOwner)
213 requires
214 valid_frame_paddr(paddr),
215 self.inv(),
216 ensures
217 *ret == old(self).slot_owner(paddr),
218 *final(self) == (Self {
219 slot_owners: old(self).slot_owners.insert(frame_to_index(paddr), *final(ret)),
220 ..*old(self)
221 }),
222 {
223 self.lemma_contains_valid_frame_paddr(paddr);
224 self.slot_owners.tracked_borrow_mut(frame_to_index(paddr))
225 }
226
227 pub open spec fn clean_inv(self) -> bool {
240 &&& self.inv()
241 &&& self.frame_obligations.len() == 0
245 }
246
247 pub open spec fn mint_frame_obligation(self, slot_idx: int) -> Self {
251 Self { frame_obligations: self.frame_obligations.insert(slot_idx), ..self }
252 }
253
254 pub open spec fn redeem_frame_obligation(self, slot_idx: int) -> Self
255 recommends
256 self.frame_obligations.count(slot_idx) > 0,
257 {
258 Self { frame_obligations: self.frame_obligations.remove(slot_idx), ..self }
259 }
260
261 pub axiom fn tracked_mint_frame_obligation(tracked &mut self, slot_idx: int) -> (tracked obl:
266 DropObligation<int>)
267 ensures
268 obl.value() == slot_idx,
269 *final(self) == old(self).mint_frame_obligation(slot_idx),
270 ;
271
272 pub axiom fn tracked_redeem_frame_obligation(
276 tracked &mut self,
277 tracked obl: DropObligation<int>,
278 )
279 requires
280 old(self).frame_obligations.count(obl.value()) > 0,
281 ensures
282 *final(self) == old(self).redeem_frame_obligation(obl.value()),
283 ;
284}
285
286}