ostd/specs/mm/page_table/cursor/
cursor_fn_specs.rs1use core::ops::Range;
2
3use vstd::prelude::*;
4
5use crate::specs::{
6 arch::{NR_LEVELS, PAGE_SIZE},
7 mm::{
8 frame::{
9 mapping::frame_to_index,
10 meta_owners::{PageUsage, is_mmio_paddr},
11 meta_region_owners::MetaRegionOwners,
12 },
13 page_table::{cursor::owners::*, is_valid_range_spec, *},
14 },
15 task::InAtomicMode,
16};
17
18use crate::mm::{
19 PagingConstsTrait, Vaddr,
20 frame::meta::{REF_COUNT_MAX, REF_COUNT_UNUSED},
21 page_table::*,
22};
23
24verus! {
25
26impl<'rcu, C: PageTableConfig, A: InAtomicMode> Cursor<'rcu, C, A> {
28 pub open spec fn cursor_new_success_conditions(va: Range<Vaddr>) -> bool {
29 &&& va.start < va.end
30 &&& va.start % C::BASE_PAGE_SIZE() == 0
31 &&& va.end % C::BASE_PAGE_SIZE() == 0
32 &&& is_valid_range_spec::<C>(va)
33 }
34
35 pub open spec fn invariants(
36 self,
37 owner: CursorOwner<'rcu, C>,
38 regions: MetaRegionOwners,
39 guards: Guards<'rcu>,
40 ) -> bool {
41 &&& owner.inv()
42 &&& self.inv()
43 &&& self.wf(owner)
44 &&& regions.inv()
45 &&& owner.children_not_locked(guards)
46 &&& owner.nodes_locked(guards)
47 &&& owner.metaregion_sound(regions)
48 &&& !owner.popped_too_high
49 }
50
51 pub open spec fn query_some_condition(self, owner: CursorOwner<'rcu, C>) -> bool {
52 owner@.present()
53 }
54
55 pub open spec fn query_panic_condition(
68 self,
69 owner: CursorOwner<'rcu, C>,
70 regions: MetaRegionOwners,
71 ) -> bool {
72 let pa = owner@.query_mapping().pa_range.start;
73 let idx = frame_to_index(pa);
74 &&& self.barrier_va.start <= self.va < self.barrier_va.end
75 &&& owner@.present()
76 &&& !is_mmio_paddr(pa)
77 &&& regions.slot_owners[idx].inner_perms.ref_count.value() >= REF_COUNT_MAX
78 }
79
80 pub open spec fn query_some_ensures(
81 self,
82 owner: CursorOwner<'rcu, C>,
83 res: PagesState<C>,
84 ) -> bool {
85 &&& owner.cur_va_range().start.reflect(res.0.start)
86 &&& owner.cur_va_range().end.reflect(res.0.end)
87 &&& res.1 is Some
88 &&& {
89 let qr = owner@.query_range();
90 owner@.query_item_spec(res.1->0) == Some(qr.start as Vaddr..qr.end as Vaddr)
91 }
92 }
93
94 pub open spec fn query_none_ensures(
95 self,
96 owner: CursorOwner<'rcu, C>,
97 res: PagesState<C>,
98 ) -> bool {
99 &&& res.1 is None
100 }
101
102 pub open spec fn jump_node_holds(self, lv: PagingLevel, va: Vaddr) -> bool {
108 let nstart = nat_align_down(self.va as nat, page_size((lv + 1) as PagingLevel) as nat);
109 &&& nstart <= va as nat
110 &&& (va as nat) - nstart < page_size((lv + 1) as PagingLevel) as nat
111 }
112
113 pub open spec fn jump_panic_condition(self, va: Vaddr) -> bool {
123 ||| va % PAGE_SIZE != 0
124 ||| (self.barrier_va.start <= va < self.barrier_va.end && forall|lv: PagingLevel|
125 #![trigger self.jump_node_holds(lv, va)]
126 self.level <= lv <= self.guard_level ==> !self.jump_node_holds(lv, va))
127 }
128
129 pub open spec fn find_next_panic_condition(self, len: usize) -> bool {
130 ||| len % PAGE_SIZE != 0
131 ||| self.va + len > self.barrier_va.end
132 }
133}
134
135impl<'rcu, C: PageTableConfig, A: InAtomicMode> CursorMut<'rcu, C, A> {
137 pub open spec fn map_panic_conditions(self, item: C::Item) -> bool {
145 ||| self.0.va >= self.0.barrier_va.end
146 ||| C::item_into_raw(item).1 > C::HIGHEST_TRANSLATION_LEVEL()
147 ||| C::item_into_raw(item).1 >= self.0.guard_level
148 ||| (!C::TOP_LEVEL_CAN_UNMAP_spec() && C::item_into_raw(item).1 >= NR_LEVELS)
149 ||| self.0.va % page_size(C::item_into_raw(item).1) != 0
150 ||| self.0.va + page_size(C::item_into_raw(item).1) > self.0.barrier_va.end
151 }
152
153 pub open spec fn item_wf(self, item: C::Item, entry_owner: EntryOwner<C>) -> bool {
155 let (paddr, level, prop) = C::item_into_raw(item);
156 &&& C::item_well_formed(item)
157 &&& entry_owner.inv()
158 &&& (entry_owner.is_absent() || Child::Frame(paddr, level, prop).wf(entry_owner))
159 }
160
161 pub open spec fn item_not_mapped(item: C::Item, regions: MetaRegionOwners) -> bool {
162 let (pa, level, prop) = C::item_into_raw(item);
163 let size = page_size(level);
164 let range = pa..(pa + size) as usize;
165 regions.paddr_range_not_mapped(range)
166 }
167
168 pub open spec fn item_slot_in_regions(item: C::Item, regions: MetaRegionOwners) -> bool {
169 let (pa, level, prop) = C::item_into_raw(item);
170 let idx = frame_to_index(pa);
171 &&& regions.slots.contains_key(idx)
172 &&& regions.slot_owners[idx].usage !is PageTable
173 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
174 != REF_COUNT_UNUSED
175 &&& C::tracked(item) ==> regions.slot_owners[idx].inner_perms.ref_count.value()
177 > 0
178 &&& C::tracked(item) ==> regions.slot_owners[idx].inner_perms.ref_count.value()
183 <= REF_COUNT_MAX
184 &&& level > 1 ==> {
186 forall|j: usize|
187 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
188 0 < j < page_size(level) / PAGE_SIZE ==> {
189 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
190 &&& regions.slots.contains_key(sub_idx)
191 &&& C::tracked(item)
192 ==> regions.slot_owners[sub_idx].inner_perms.ref_count.value()
193 != REF_COUNT_UNUSED
194 &&& C::tracked(item)
195 ==> regions.slot_owners[sub_idx].inner_perms.ref_count.value()
196 > 0
197 &&& C::tracked(item)
200 ==> regions.slot_owners[sub_idx].inner_perms.ref_count.value()
201 <= REF_COUNT_MAX
202 }
203 }
204 }
205
206 pub open spec fn map_item_ensures(
207 self,
208 item: C::Item,
209 old_view: CursorView<C>,
210 new_view: CursorView<C>,
211 ) -> bool {
212 let (pa, level, prop) = C::item_into_raw(item);
213 new_view == old_view.map_spec(pa, page_size(level), prop)
214 }
215}
216
217}