ostd/specs/mm/page_table/cursor/
tree_lemmas.rs1use vstd::{
4 arithmetic::div_mod::{lemma_small_mod, lemma_sub_mod_noop},
5 prelude::*,
6};
7use vstd_extra::{arithmetic::lemma_nat_align_down_sound, ghost_tree::*, ownership::*};
8
9use crate::specs::{
10 arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE},
11 mm::page_table::{
12 cursor::owners::{CursorContinuation, CursorOwner},
13 node::entry_owners::EntryOwner,
14 owners::*,
15 },
16};
17
18use crate::arch::mm::PagingConsts;
19use crate::mm::{Paddr, PagingLevel, Vaddr, page_prop::PageProperty, page_size, page_table::*};
20use core::ops::Range;
21
22verus! {
23
24impl<'rcu, C: PageTableConfig> CursorContinuation<'rcu, C> {
26 pub proof fn map_children_lift(
28 self,
29 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
30 g: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
31 )
32 requires
33 self.inv(),
34 self.map_children(f),
35 OwnerSubtree::implies(f, g),
36 ensures
37 self.map_children(g),
38 {
39 reveal(CursorContinuation::map_children);
40 assert forall|j: int|
41 #![auto]
42 0 <= j < self.children.len()
43 && self.children[j] is Some implies self.children[j].unwrap().subtree_satisfies(
44 self.path().push_tail(j),
45 g,
46 ) by {
47 self.lemma_inv_children_unroll(j);
48 OwnerSubtree::lemma_subtree_satisfies_implies(
49 self.children[j].unwrap(),
50 self.path().push_tail(j),
51 f,
52 g,
53 );
54 };
55 }
56
57 pub proof fn map_children_lift_skip_idx(
61 self,
62 cont0: Self,
63 idx: int,
64 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
65 g: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
66 )
67 requires
68 0 <= idx < NR_ENTRIES,
69 OwnerSubtree::implies(f, g),
70 cont0.inv(),
71 cont0.map_children(f),
72 self.path() == cont0.path(),
73 self.children.len() == cont0.children.len(),
74 forall|j: int|
75 #![auto]
76 0 <= j < NR_ENTRIES && j != idx ==> self.children[j] == cont0.children[j],
77 self.children[idx] is Some ==> self.children[idx]->0.subtree_satisfies(
78 self.path().push_tail(idx as int),
79 g,
80 ),
81 ensures
82 self.map_children(g),
83 {
84 reveal(CursorContinuation::map_children);
85 assert forall|j: int|
86 #![auto]
87 0 <= j < self.children.len()
88 && self.children[j] is Some implies self.children[j].unwrap().subtree_satisfies(
89 self.path().push_tail(j),
90 g,
91 ) by {
92 if j != idx {
93 cont0.lemma_inv_children_unroll(j);
94 OwnerSubtree::lemma_subtree_satisfies_implies(
95 cont0.children[j].unwrap(),
96 cont0.path().push_tail(j),
97 f,
98 g,
99 );
100 }
101 };
102 }
103
104 pub proof fn as_subtree_restore(self, child: Self)
105 requires
106 self.inv(),
107 child.inv(),
108 self.all_but_index_some(),
109 child.all_some(),
110 ensures
111 self.restore(child).0.as_subtree() == self.put_child(child.as_subtree()).as_subtree(),
112 {
113 assert(self.put_child(child.as_subtree()).children == self.children.update(
114 self.idx as int,
115 Some(child.as_subtree()),
116 ));
117 }
118}
119
120impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
122 pub proof fn map_children_implies(
123 self,
124 f: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
125 g: spec_fn(EntryOwner<C>, TreePath<NR_ENTRIES>) -> bool,
126 )
127 requires
128 self.inv(),
129 OwnerSubtree::implies(f, g),
130 forall|i: int|
131 #![trigger self.continuations[i]]
132 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(f),
133 ensures
134 forall|i: int|
135 #![trigger self.continuations[i]]
136 self.level - 1 <= i < NR_LEVELS ==> self.continuations[i].map_children(g),
137 {
138 assert forall|i: int|
139 #![trigger self.continuations[i]]
140 self.level - 1 <= i < NR_LEVELS implies self.continuations[i].map_children(g) by {
141 reveal(CursorContinuation::map_children);
142 let cont = self.continuations[i];
143 reveal(CursorContinuation::inv_children);
144 assert forall|j: int|
145 #![trigger cont.children[j]]
146 0 <= j < cont.children.len()
147 && cont.children[j] is Some implies cont.children[j].unwrap().subtree_satisfies(
148 cont.path().push_tail(j),
149 g,
150 ) by {
151 cont.lemma_inv_children_unroll(j);
152 OwnerSubtree::lemma_subtree_satisfies_implies(
153 cont.children[j].unwrap(),
154 cont.path().push_tail(j),
155 f,
156 g,
157 );
158 }
159 }
160 }
161
162 pub proof fn cur_entry_node_implies_level_gt_1(self)
164 requires
165 self.inv(),
166 self.cur_entry_owner().is_node(),
167 ensures
168 self.level > 1,
169 {
170 self.lemma_cur_subtree_inv();
171 }
172
173 #[verifier::spinoff_prover]
180 pub proof fn frame_not_fits_implies_level_gt_1(
181 self,
182 cur_entry_fits_range: bool,
183 cur_va: Vaddr,
184 end: Vaddr,
185 )
186 requires
187 self.inv(),
188 self.cur_entry_owner().is_frame(),
189 !cur_entry_fits_range,
190 cur_va < end,
191 cur_va == self.cur_va(),
193 cur_entry_fits_range == (cur_va == self.cur_va_range().start && self.cur_va_range().end
195 <= end),
196 cur_va as nat % PAGE_SIZE as nat == 0,
198 end as nat % PAGE_SIZE as nat == 0,
199 ensures
200 self.level > 1,
201 {
202 if self.level == 1 {
203 crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_base::<
204 PagingConsts,
205 >();
206 lemma_nat_align_down_sound(cur_va as nat, PAGE_SIZE as nat);
207 lemma_sub_mod_noop(end as int, cur_va as int, PAGE_SIZE as int);
208 if end - cur_va < PAGE_SIZE {
209 lemma_small_mod((end - cur_va) as nat, PAGE_SIZE as nat);
210 assert(false);
211 }
212 }
213 }
214}
215
216}