1use vstd::{atomic::*, cell::pcell_maybe_uninit, prelude::*, simple_pptr::*};
2use vstd_extra::{
3 cast_ptr::{self, Repr},
4 ghost_tree::TreePath,
5 ownership::*,
6 resource::ghost_resource::count_auth::{Count, CountResource},
7};
8
9use crate::specs::{arch::NR_ENTRIES, mm::frame::linked_list::linked_list_owners::StoredLink};
10
11use super::*;
12use crate::mm::{
13 Paddr, PagingLevel, Vaddr,
14 frame::{
15 AnyFrameMeta,
16 meta::{
17 META_SLOT_SIZE, MetaSlot, REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED,
18 mapping::meta_to_frame,
19 },
20 },
21 kspace::FRAME_METADATA_RANGE,
22};
23
24verus! {
25
26#[allow(non_camel_case_types)]
27pub ghost enum MetaSlotStatus {
28 UNUSED,
29 UNIQUE,
30 SHARED,
31 OVERFLOW,
32 UNDER_CONSTRUCTION,
33}
34
35pub ghost enum PageUsage {
36 Unused,
39 Reserved,
41 Frame,
43 PageTable,
45 Meta,
47 Kernel,
49 MMIO,
53}
54
55pub uninterp spec fn is_mmio_paddr(pa: Paddr) -> bool;
60
61pub broadcast axiom fn axiom_mmio_usage_iff_mmio_paddr(slot: MetaSlotOwner)
67 ensures
68 (#[trigger] slot.usage == PageUsage::MMIO) <==> is_mmio_paddr(
69 meta_to_frame(slot.slot_vaddr),
70 ),
71;
72
73pub axiom fn axiom_mmio_paddr_huge_page_closed(pa: Paddr, page_size: usize, offset: usize)
80 requires
81 pa % page_size == 0,
82 offset < page_size,
83 ensures
84 is_mmio_paddr((pa + offset) as Paddr) == is_mmio_paddr(pa),
85;
86
87pub struct StoredPageTablePageMeta {
88 pub nr_children: pcell_maybe_uninit::PCell<u16>,
89 pub stray: pcell_maybe_uninit::PCell<bool>,
90 pub level: PagingLevel,
91 pub lock: PAtomicU8,
92}
93
94pub enum MetaSlotStorage {
95 Empty([u8; 39]),
96 Untyped,
97 FrameLink(StoredLink),
98 PTNode(StoredPageTablePageMeta),
99}
100
101unsafe impl AnyFrameMeta for MetaSlotStorage {
105 uninterp spec fn vtable_ptr(&self) -> usize;
106}
107
108impl Repr<MetaSlotStorage> for MetaSlotStorage {
109 type ReprPerm = ();
110
111 open spec fn wf(slot: MetaSlotStorage, perm: ()) -> bool {
112 true
113 }
114
115 open spec fn to_repr_spec(self, perm: ()) -> (MetaSlotStorage, ()) {
116 (self, ())
117 }
118
119 fn to_repr(self, Tracked(perm): Tracked<&mut ()>) -> MetaSlotStorage {
120 self
121 }
122
123 open spec fn from_repr_spec(slot: MetaSlotStorage, perm: ()) -> Self {
124 slot
125 }
126
127 fn from_repr(slot: MetaSlotStorage, Tracked(perm): Tracked<&()>) -> Self {
128 slot
129 }
130
131 fn from_borrowed<'a>(slot: &'a MetaSlotStorage, Tracked(perm): Tracked<&'a ()>) -> &'a Self {
132 slot
133 }
134
135 fn from_borrowed_mut<'a>(
136 slot: &'a mut MetaSlotStorage,
137 Tracked(perm): Tracked<&'a mut ()>,
138 ) -> &'a mut Self {
139 slot
140 }
141
142 proof fn from_to_repr(self, perm: ()) {
143 }
144
145 proof fn to_from_repr(slot: MetaSlotStorage, perm: ()) {
146 }
147
148 proof fn to_repr_wf(self, perm: ()) {
149 }
150}
151
152pub tracked struct MetadataPerm {
154 pub storage_perm: pcell_maybe_uninit::PointsTo<MetaSlotStorage>,
155 pub vtable_ptr_perm: vstd::simple_pptr::PointsTo<usize>,
156}
157
158pub const REF_COUNT_MAX_USIZE: usize = REF_COUNT_MAX as usize;
159
160pub type FracMetadataPerm = Count<MetadataPerm, REF_COUNT_MAX_USIZE>;
162
163pub type FracMetadataPermResource = CountResource<MetadataPerm, REF_COUNT_MAX_USIZE>;
165
166pub tracked struct MetaSlotOwner {
171 pub metadata_perm: FracMetadataPermResource,
172 pub ref_count_perm: PermissionU64,
173 pub in_list_perm: PermissionU64,
174 pub ghost slot_vaddr: Vaddr,
175 pub ghost usage: PageUsage,
176 pub ghost paths_in_pt: Set<TreePath<NR_ENTRIES>>,
181}
182
183impl MetaSlotOwner {
184 pub open spec fn same_permissions(self, other: Self) -> bool {
185 &&& self.metadata_perm == other.metadata_perm
186 &&& self.ref_count_perm == other.ref_count_perm
187 &&& self.in_list_perm == other.in_list_perm
188 }
189
190 pub open spec fn ref_count(self) -> u64 {
191 self.ref_count_perm.value()
192 }
193
194 pub open spec fn metadata_perm(self) -> MetadataPerm {
195 self.metadata_perm.resource()
196 }
197
198 pub open spec fn storage_perm(self) -> pcell_maybe_uninit::PointsTo<MetaSlotStorage> {
199 self.metadata_perm().storage_perm
200 }
201
202 pub open spec fn vtable_ptr_perm(self) -> vstd::simple_pptr::PointsTo<usize> {
203 self.metadata_perm().vtable_ptr_perm
204 }
205
206 pub proof fn tracked_borrow_metadata_perm(tracked &self) -> tracked &MetadataPerm
207 requires
208 !self.metadata_perm.is_resource_vacant(),
209 returns
210 self.metadata_perm(),
211 {
212 self.metadata_perm.tracked_borrow()
213 }
214}
215
216pub open spec fn typed_meta_wf<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
218 slot_perm: vstd::simple_pptr::PointsTo<MetaSlot>,
219 metadata_perm: MetadataPerm,
220 repr_perm: M::ReprPerm,
221) -> bool {
222 &&& slot_perm.is_init()
223 &&& MetaSlot::perms_related(slot_perm, metadata_perm)
224 &&& M::wf(metadata_perm.storage_perm.value(), repr_perm)
225}
226
227pub open spec fn typed_meta_value<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
229 metadata_perm: MetadataPerm,
230 repr_perm: M::ReprPerm,
231) -> M {
232 M::from_repr_spec(metadata_perm.storage_perm.value(), repr_perm)
233}
234
235pub fn borrow_meta<'a, M: AnyFrameMeta + Repr<MetaSlotStorage>>(
236 ptr: cast_ptr::ReprPtr<MetaSlotStorage, M>,
237 Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>,
238 Tracked(metadata_perm): Tracked<&'a MetadataPerm>,
239 Tracked(repr_perm): Tracked<&'a M::ReprPerm>,
240) -> &'a M
241 requires
242 ptr.addr() == slot_perm.addr(),
243 typed_meta_wf::<M>(*slot_perm, *metadata_perm, *repr_perm),
244 returns
245 typed_meta_value::<M>(*metadata_perm, *repr_perm),
246{
247 let slot = PPtr::<MetaSlot>::from_addr(ptr.addr()).borrow(Tracked(slot_perm));
248 M::from_borrowed(slot.storage.borrow(Tracked(&metadata_perm.storage_perm)), Tracked(repr_perm))
249}
250
251pub fn borrow_meta_mut<'a, M: AnyFrameMeta + Repr<MetaSlotStorage>>(
252 ptr: cast_ptr::ReprPtr<MetaSlotStorage, M>,
253 Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>,
254 Tracked(metadata_perms): Tracked<&'a mut MetadataPerm>,
255 Tracked(repr_perm): Tracked<&'a mut M::ReprPerm>,
256) -> (res: &'a mut M)
257 requires
258 ptr.addr() == slot_perm.addr(),
259 typed_meta_wf::<M>(*slot_perm, *old(metadata_perms), *old(repr_perm)),
260 ensures
261 *res == typed_meta_value::<M>(*old(metadata_perms), *old(repr_perm)),
262 *final(res) == typed_meta_value::<M>(*final(metadata_perms), *final(repr_perm)),
263 typed_meta_wf::<M>(*slot_perm, *final(metadata_perms), *final(repr_perm)),
264{
265 let slot = PPtr::<MetaSlot>::from_addr(ptr.addr()).borrow(Tracked(slot_perm));
266 M::from_borrowed_mut(
267 slot.storage.borrow_mut(Tracked(&mut metadata_perms.storage_perm)),
268 Tracked(repr_perm),
269 )
270}
271
272impl Inv for MetaSlotOwner {
273 open spec fn inv(self) -> bool {
274 &&& self.ref_count() == REF_COUNT_UNUSED ==> {
275 &&& self.metadata_perm.is_full()
276 &&& self.storage_perm().is_uninit()
277 &&& self.vtable_ptr_perm().is_uninit()
278 &&& self.in_list_perm.value()
279 == 0
280 &&& (self.usage != PageUsage::MMIO ==> self.paths_in_pt.is_empty())
282 }
283 &&& self.ref_count() == REF_COUNT_UNIQUE ==> {
284 &&& self.metadata_perm.is_resource_vacant()
285 &&& (self.usage != PageUsage::MMIO ==> self.paths_in_pt.is_empty())
286 }
287 &&& 0 < self.ref_count() <= REF_COUNT_MAX ==> {
288 &&& self.metadata_perm.frac() + self.ref_count() == REF_COUNT_MAX
289 &&& self.vtable_ptr_perm().is_init()
290 &&& self.storage_perm().is_init()
291 &&& self.in_list_perm.value() == 0
292 }
293 &&& REF_COUNT_MAX < self.ref_count() < REF_COUNT_UNIQUE ==> { false }
294 &&& self.ref_count() == 0 ==> {
295 &&& self.in_list_perm.value() == 0
296 }
297 &&& FRAME_METADATA_RANGE.start <= self.slot_vaddr < FRAME_METADATA_RANGE.end
298 &&& self.slot_vaddr % META_SLOT_SIZE == 0
299 }
300}
301
302impl OwnerOf for MetaSlot {
303 type Owner = MetaSlotOwner;
304
305 open spec fn wf(self, owner: Self::Owner) -> bool {
306 &&& self.ref_count.id() == owner.ref_count_perm.id()
307 &&& self.in_list.id() == owner.in_list_perm.id()
308 &&& owner.metadata_perm.not_empty() ==> {
309 &&& self.storage.id() == owner.storage_perm().id()
310 &&& self.vtable_ptr == owner.vtable_ptr_perm().pptr()
311 }
312 }
313}
314
315pub exec fn write_metadata_into_storage<M: AnyFrameMeta + Repr<MetaSlotStorage>>(
318 cell: &pcell_maybe_uninit::PCell<MetaSlotStorage>,
319 Tracked(metadata_perms): Tracked<&mut MetadataPerm>,
320 Tracked(repr_perm): Tracked<&mut M::ReprPerm>,
321 metadata: M,
322)
323 requires
324 cell.id() == old(metadata_perms).storage_perm.id(),
325 ensures
326 final(metadata_perms).storage_perm.id() == old(metadata_perms).storage_perm.id(),
327 final(metadata_perms).storage_perm.is_init(),
328 final(metadata_perms).vtable_ptr_perm == old(metadata_perms).vtable_ptr_perm,
329 M::wf(final(metadata_perms).storage_perm.value(), *final(repr_perm)),
330 M::from_repr_spec(final(metadata_perms).storage_perm.value(), *final(repr_perm))
331 == metadata,
332{
333 proof {
334 M::from_to_repr(metadata, *repr_perm);
335 M::to_repr_wf(metadata, *repr_perm);
336 }
337 let repr = metadata.to_repr(Tracked(repr_perm));
338 cell.write(Tracked(&mut metadata_perms.storage_perm), repr);
339}
340
341}