ostd/specs/mm/page_table/cursor/
cursor_fn_specs.rs1use vstd::prelude::*;
2
3use crate::mm::page_table::*;
4use crate::mm::{PagingConstsTrait, Vaddr};
5use crate::specs::arch::mm::{NR_LEVELS, PAGE_SIZE};
6use crate::specs::mm::frame::mapping::frame_to_index;
7use crate::specs::mm::frame::meta_owners::{REF_COUNT_MAX, REF_COUNT_UNUSED, is_mmio_paddr};
8use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
9use crate::specs::mm::page_table::cursor::owners::*;
10use crate::specs::mm::page_table::*;
11use crate::specs::task::InAtomicMode;
12
13use core::ops::Range;
14
15verus! {
16
17impl<'rcu, C: PageTableConfig, A: InAtomicMode> Cursor<'rcu, C, A> {
19 pub open spec fn cursor_new_success_conditions(va: &Range<Vaddr>) -> bool {
20 &&& va.start < va.end
21 &&& va.start % C::BASE_PAGE_SIZE() == 0
22 &&& va.end % C::BASE_PAGE_SIZE() == 0
23 &&& crate::mm::page_table::is_valid_range_spec::<C>(va)
24 }
25
26 pub open spec fn invariants(
27 self,
28 owner: CursorOwner<'rcu, C>,
29 regions: MetaRegionOwners,
30 guards: Guards<'rcu>,
31 ) -> bool {
32 &&& owner.inv()
33 &&& self.inv()
34 &&& self.wf(owner)
35 &&& regions.inv()
36 &&& owner.children_not_locked(guards)
37 &&& owner.nodes_locked(guards)
38 &&& owner.metaregion_sound(regions)
39 &&& !owner.popped_too_high
40 }
41
42 pub open spec fn query_some_condition(self, owner: CursorOwner<'rcu, C>) -> bool {
43 self.model(owner).present()
44 }
45
46 pub open spec fn query_panic_condition(
59 self,
60 owner: CursorOwner<'rcu, C>,
61 regions: MetaRegionOwners,
62 ) -> bool {
63 let pa = owner@.query_mapping().pa_range.start;
64 let idx = frame_to_index(pa);
65 &&& self.barrier_va.start <= self.va < self.barrier_va.end
66 &&& owner@.present()
67 &&& !is_mmio_paddr(pa)
68 &&& regions.slot_owners[idx].inner_perms.ref_count.value() >= REF_COUNT_MAX
69 }
70
71 pub open spec fn query_some_ensures(
72 self,
73 owner: CursorOwner<'rcu, C>,
74 res: PagesState<C>,
75 ) -> bool {
76 &&& owner.cur_va_range().start.reflect(res.0.start)
77 &&& owner.cur_va_range().end.reflect(res.0.end)
78 &&& res.1 is Some
79 &&& {
80 let qr = owner@.query_range();
81 owner@.query_item_spec(res.1.unwrap()) == Some(qr.start as Vaddr..qr.end as Vaddr)
82 }
83 }
84
85 pub open spec fn query_none_ensures(
86 self,
87 owner: CursorOwner<'rcu, C>,
88 res: PagesState<C>,
89 ) -> bool {
90 &&& res.1 is None
91 }
92
93 pub open spec fn jump_node_holds(self, lv: PagingLevel, va: Vaddr) -> bool {
99 let nstart = nat_align_down(self.va as nat, page_size((lv + 1) as PagingLevel) as nat);
100 &&& nstart <= va as nat
101 &&& (va as nat) - nstart < page_size((lv + 1) as PagingLevel) as nat
102 }
103
104 pub open spec fn jump_panic_condition(self, va: Vaddr) -> bool {
114 ||| va % PAGE_SIZE != 0
115 ||| (self.barrier_va.start <= va < self.barrier_va.end && forall|lv: PagingLevel|
116 #![trigger self.jump_node_holds(lv, va)]
117 self.level <= lv <= self.guard_level ==> !self.jump_node_holds(lv, va))
118 }
119
120 pub open spec fn find_next_panic_condition(self, len: usize) -> bool {
121 ||| len % PAGE_SIZE != 0
122 ||| self.va + len > self.barrier_va.end
123 }
124}
125
126impl<'rcu, C: PageTableConfig, A: InAtomicMode> CursorMut<'rcu, C, A> {
128 pub open spec fn map_panic_conditions(self, item: C::Item) -> bool {
136 ||| self.0.va >= self.0.barrier_va.end
137 ||| C::item_into_raw(item).1 > C::HIGHEST_TRANSLATION_LEVEL()
138 ||| C::item_into_raw(item).1 >= self.0.guard_level
139 ||| (!C::TOP_LEVEL_CAN_UNMAP_spec() && C::item_into_raw(item).1 >= NR_LEVELS)
140 ||| self.0.va % page_size(C::item_into_raw(item).1) != 0
141 ||| self.0.va + page_size(C::item_into_raw(item).1) > self.0.barrier_va.end
142 }
143
144 pub open spec fn item_wf(self, item: C::Item, entry_owner: EntryOwner<C>) -> bool {
146 let (paddr, level, prop) = C::item_into_raw(item);
147 &&& entry_owner.inv()
148 &&& (entry_owner.is_absent() || Child::Frame(paddr, level, prop).wf(entry_owner))
149 }
150
151 pub open spec fn item_not_mapped(item: C::Item, regions: MetaRegionOwners) -> bool {
152 let (pa, level, prop) = C::item_into_raw(item);
153 let size = page_size(level);
154 let range = pa..(pa + size) as usize;
155 regions.paddr_range_not_mapped(range)
156 }
157
158 pub open spec fn item_slot_in_regions(item: C::Item, regions: MetaRegionOwners) -> bool {
159 let (pa, level, prop) = C::item_into_raw(item);
160 let idx = frame_to_index(pa);
161 &&& regions.slots.contains_key(idx)
162 &&& regions.slot_owners[idx].inner_perms.ref_count.value()
163 != REF_COUNT_UNUSED
164 &&& C::tracked(item) ==> regions.slot_owners[idx].inner_perms.ref_count.value()
166 > 0
167 &&& level > 1 ==> {
169 forall|j: usize|
170 #![trigger frame_to_index((pa + j * PAGE_SIZE) as usize)]
171 0 < j < page_size(level) / PAGE_SIZE ==> {
172 let sub_idx = frame_to_index((pa + j * PAGE_SIZE) as usize);
173 &&& regions.slots.contains_key(sub_idx)
174 &&& C::tracked(item)
175 ==> regions.slot_owners[sub_idx].inner_perms.ref_count.value()
176 != REF_COUNT_UNUSED
177 &&& C::tracked(item)
178 ==> regions.slot_owners[sub_idx].inner_perms.ref_count.value() > 0
179 }
180 }
181 }
182
183 pub open spec fn map_item_ensures(
184 self,
185 item: C::Item,
186 old_view: CursorView<C>,
187 new_view: CursorView<C>,
188 ) -> bool {
189 let (pa, level, prop) = C::item_into_raw(item);
190 new_view == old_view.map_spec(pa, page_size(level), prop)
191 }
192}
193
194}