ostd/specs/mm/frame/
meta_region_owners.rs1use vstd::atomic::*;
2use vstd::cell;
3use vstd::prelude::*;
4use vstd::simple_pptr::{self, *};
5
6use core::ops::Range;
7
8use vstd_extra::cast_ptr::Repr;
9use vstd_extra::ghost_tree::TreePath;
10use vstd_extra::ownership::*;
11
12use super::meta_owners::{
13 MetaPerm, MetaSlotModel, MetaSlotOwner, MetaSlotStorage, REF_COUNT_UNUSED,
14};
15use super::*;
16use crate::mm::frame::meta::{
17 mapping::{frame_to_index_spec, frame_to_meta, max_meta_slots, meta_addr, META_SLOT_SIZE},
18 AnyFrameMeta, MetaSlot,
19};
20use crate::mm::Paddr;
21use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
22use crate::specs::arch::mm::{MAX_PADDR, NR_ENTRIES, PAGE_SIZE};
23
24verus! {
25
26pub struct MetaRegion;
29
30pub tracked struct MetaRegionOwners {
51 pub slots: Map<usize, simple_pptr::PointsTo<MetaSlot>>,
52 pub slot_owners: Map<usize, MetaSlotOwner>,
53}
54
55pub ghost struct MetaRegionModel {
56 pub slots: Map<usize, MetaSlotModel>,
57}
58
59impl Inv for MetaRegionOwners {
60 open spec fn inv(self) -> bool {
61 &&& self.slots.dom().finite()
62 &&& {
63 forall|i: usize| i < max_meta_slots() <==> #[trigger] self.slot_owners.contains_key(i)
65 }
66 &&& { forall|i: usize| #[trigger] self.slots.contains_key(i) ==> i < max_meta_slots() }
67 &&& {
68 forall|i: usize| #[trigger]
69 self.slots.contains_key(i) ==> {
70 &&& self.slot_owners.contains_key(i)
71 &&& self.slot_owners[i].inv()
72 &&& self.slots[i].is_init()
73 &&& self.slots[i].addr() == meta_addr(i)
74 &&& self.slots[i].value().wf(self.slot_owners[i])
75 &&& self.slot_owners.contains_key(i)
76 &&& self.slot_owners[i].self_addr == self.slots[i].addr()
77 }
78 }
79 &&& {
80 forall|i: usize| #[trigger]
81 self.slot_owners.contains_key(i) ==> {
82 &&& self.slot_owners[i].inv()
83 }
84 }
85 }
86}
87
88impl Inv for MetaRegionModel {
89 open spec fn inv(self) -> bool {
90 &&& self.slots.dom().finite()
91 &&& forall|i: usize| i < max_meta_slots() <==> #[trigger] self.slots.contains_key(i)
92 &&& forall|i: usize| #[trigger] self.slots.contains_key(i) ==> self.slots[i].inv()
93 }
94}
95
96impl View for MetaRegionOwners {
97 type V = MetaRegionModel;
98
99 open spec fn view(&self) -> <Self as View>::V {
100 let slots = self.slot_owners.map_values(|s: MetaSlotOwner| s@);
101 MetaRegionModel { slots }
102 }
103}
104
105impl InvView for MetaRegionOwners {
106 axiom fn view_preserves_inv(self);
108}
109
110impl OwnerOf for MetaRegion {
111 type Owner = MetaRegionOwners;
112
113 open spec fn wf(self, owner: Self::Owner) -> bool {
114 true
115 }
116}
117
118impl ModelOf for MetaRegion {
119
120}
121
122impl MetaRegionOwners {
123 pub open spec fn ref_count(self, i: usize) -> (res: u64)
124 recommends
125 self.inv(),
126 i < max_meta_slots() as usize,
127 {
128 self.slot_owners[i].inner_perms.ref_count.value()
129 }
130
131 pub open spec fn paddr_range_in_region(self, range: Range<Paddr>) -> bool
132 recommends
133 self.inv(),
134 range.start < range.end < MAX_PADDR,
135 {
136 forall|paddr: Paddr|
137 #![trigger frame_to_index_spec(paddr)]
138 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
139 ==> self.slots.contains_key(frame_to_index_spec(paddr))
140 }
141
142 pub open spec fn paddr_range_not_mapped(self, range: Range<Paddr>) -> bool
143 recommends
144 self.inv(),
145 range.start < range.end < MAX_PADDR,
146 {
147 forall|paddr: Paddr|
148 #![trigger frame_to_index_spec(paddr)]
149 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
150 ==> self.slot_owners[frame_to_index_spec(paddr)].paths_in_pt.is_empty()
151 }
152
153 pub open spec fn paddr_range_not_in_region(self, range: Range<Paddr>) -> bool
154 recommends
155 self.inv(),
156 range.start < range.end < MAX_PADDR,
157 {
158 forall|paddr: Paddr|
159 #![trigger frame_to_index_spec(paddr)]
160 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
161 ==> !self.slots.contains_key(frame_to_index_spec(paddr))
162 }
163
164 pub proof fn paddr_not_mapped_at(self, range: Range<Paddr>, paddr: Paddr)
166 requires
167 self.paddr_range_not_mapped(range),
168 range.start <= paddr,
169 paddr < range.end,
170 paddr % PAGE_SIZE == 0,
171 ensures
172 self.slot_owners[frame_to_index_spec(paddr)].paths_in_pt.is_empty(),
173 {
174 }
177
178 pub proof fn inv_implies_correct_addr(self, paddr: usize)
179 requires
180 paddr < MAX_PADDR,
181 paddr % PAGE_SIZE == 0,
182 self.inv(),
183 ensures
184 self.slot_owners.contains_key(frame_to_index_spec(paddr) as usize),
185 {
186 assert((frame_to_index_spec(paddr)) < max_meta_slots() as usize);
187 }
188
189 pub axiom fn sync_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
190 tracked &mut self,
191 index: usize,
192 perm: &MetaPerm<M>,
193 )
194 ensures
195 final(self).slots == old(self).slots.insert(index, perm.points_to),
196 final(self).slot_owners == old(self).slot_owners;
197
198 pub axiom fn copy_perm<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
199 tracked &mut self,
200 index: usize,
201 ) -> (tracked perm: MetaPerm<M>)
202 requires
203 old(self).slots.contains_key(index),
204 ensures
205 perm.points_to == old(self).slots[index],
206 final(self).slots == old(self).slots.remove(index),
207 final(self).slot_owners == old(self).slot_owners;
208
209 pub axiom fn frame_slot_perm_insert_preserves_inv(
215 self,
216 idx: usize,
217 perm: simple_pptr::PointsTo<MetaSlot>,
218 new_regions: MetaRegionOwners,
219 )
220 requires
221 self.inv(),
222 perm.addr() == meta_addr(idx),
223 perm.is_init(),
224 perm.value().wf(self.slot_owners[idx]),
225 self.slot_owners.contains_key(idx),
226 self.slot_owners[idx].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
227 new_regions.slots == self.slots.insert(idx, perm),
228 new_regions.slot_owners == self.slot_owners,
229 ensures
230 new_regions.inv();
231}
232
233}