ostd/specs/mm/page_table/
mapping_set_lemmas.rs1use vstd::prelude::*;
2use vstd::set_lib::*;
3
4use crate::mm::Vaddr;
5use crate::specs::arch::mm::{MAX_USERSPACE_VADDR, PAGE_SIZE};
6use crate::specs::arch::MAX_PADDR;
7
8use super::view::Mapping;
9
10verus! {
11
12pub open spec fn wf_mapping_set(s: Set<Mapping>) -> bool {
14 &&& s.finite()
15 &&& forall|m: Mapping| #![auto] s.contains(m) ==> m.inv()
16 &&& forall|m: Mapping, n: Mapping| #![auto]
17 s.contains(m) && s.contains(n) && m != n ==>
18 m.va_range.end <= n.va_range.start || n.va_range.end <= m.va_range.start
19}
20
21pub proof fn lemma_mapping_set_cardinality_in_range(s: Set<Mapping>, lo: int, hi: int)
27 requires
28 wf_mapping_set(s),
29 forall|m: Mapping| #[trigger] s.contains(m) ==> lo <= m.va_range.start && m.va_range.end <= hi,
30 lo <= hi,
31 ensures
32 s.len() * PAGE_SIZE <= hi - lo,
33 decreases s.len()
34{
35 if s.len() != 0 {
36 let m = s.choose();
37 let rest = s.remove(m);
38 vstd::set::axiom_set_remove_len(s, m);
39 vstd::set::axiom_set_remove_finite(s, m);
40 assert(m.inv());
41
42 let below = rest.filter(|n: Mapping| n.va_range.end <= m.va_range.start);
43 let above = rest.filter(|n: Mapping| n.va_range.start >= m.va_range.end);
44
45 assert(rest =~= below.union(above)) by {
46 assert forall|n: Mapping| rest.contains(n)
47 implies below.contains(n) || above.contains(n) by {
48 assert(s.contains(n) && n != m);
49 };
50 };
51
52 vstd::set::axiom_set_intersect_finite::<Mapping>(
53 rest, Set::new(|n: Mapping| n.va_range.end <= m.va_range.start));
54 vstd::set::axiom_set_intersect_finite::<Mapping>(
55 rest, Set::new(|n: Mapping| n.va_range.start >= m.va_range.end));
56
57 assert(below.disjoint(above)) by {
58 assert forall|n: Mapping| below.contains(n) implies !above.contains(n) by {
59 if above.contains(n) {
60 assert(n.inv());
61 }
62 };
63 };
64
65 vstd::set_lib::lemma_set_disjoint_lens(below, above);
66 assert(rest.len() == below.len() + above.len());
67
68 assert(wf_mapping_set(below)) by {
69 assert forall|a: Mapping, b: Mapping|
70 #[trigger] below.contains(a) && #[trigger] below.contains(b) && a != b implies
71 a.va_range.end <= b.va_range.start || b.va_range.end <= a.va_range.start by {
72 assert(s.contains(a) && s.contains(b));
73 };
74 };
75 assert(wf_mapping_set(above)) by {
76 assert forall|a: Mapping, b: Mapping|
77 #[trigger] above.contains(a) && #[trigger] above.contains(b) && a != b implies
78 a.va_range.end <= b.va_range.start || b.va_range.end <= a.va_range.start by {
79 assert(s.contains(a) && s.contains(b));
80 };
81 };
82
83 lemma_mapping_set_cardinality_in_range(below, lo, m.va_range.start);
84 lemma_mapping_set_cardinality_in_range(above, m.va_range.end, hi);
85
86 assert(m.page_size >= PAGE_SIZE);
87 assert(m.page_size == m.va_range.end - m.va_range.start);
88 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
89 PAGE_SIZE as int, (below.len() + above.len()) as int, 1);
90 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
91 PAGE_SIZE as int, below.len() as int, above.len() as int);
92 }
93}
94
95pub proof fn lemma_mapping_set_cardinality_bound(s: Set<Mapping>, bound: usize)
98 requires
99 wf_mapping_set(s),
100 forall|m: Mapping| #[trigger] s.contains(m) ==> 0 <= m.va_range.start && m.va_range.end <= bound as int,
101 ensures
102 s.len() <= bound / PAGE_SIZE,
103{
104 lemma_mapping_set_cardinality_in_range(s, 0, bound as int);
105 vstd::arithmetic::div_mod::lemma_fundamental_div_mod(bound as int, PAGE_SIZE as int);
106 vstd::arithmetic::div_mod::lemma_div_pos_is_pos(bound as int, PAGE_SIZE as int);
107 if s.len() > bound / PAGE_SIZE {
108 vstd::arithmetic::mul::lemma_mul_inequality(
109 bound as int / PAGE_SIZE as int + 1,
110 s.len() as int,
111 PAGE_SIZE as int,
112 );
113 vstd::arithmetic::mul::lemma_mul_is_distributive_add(
114 PAGE_SIZE as int,
115 bound as int / PAGE_SIZE as int,
116 1,
117 );
118 }
119}
120
121pub proof fn lemma_mapping_set_cardinality_fits_usize(s: Set<Mapping>)
128 requires
129 wf_mapping_set(s),
130 forall|m: Mapping| #[trigger] s.contains(m)
131 ==> m.va_range.end <= 0x0000_8000_0000_0000_usize as int,
132 ensures
133 s.len() < usize::MAX,
134{
135 admit();
141 lemma_mapping_set_cardinality_bound(s, 0x0000_8000_0000_0000_usize);
142 assert(0x0000_8000_0000_0000_usize / PAGE_SIZE < usize::MAX) by (compute_only);
143}
144
145pub proof fn lemma_wf_subset(s: Set<Mapping>, sub: Set<Mapping>)
147 requires
148 wf_mapping_set(s),
149 sub.subset_of(s),
150 sub.finite(),
151 ensures
152 wf_mapping_set(sub),
153{
154 assert forall|m: Mapping| #![auto] sub.contains(m) implies m.inv() by {};
155 assert forall|m: Mapping, n: Mapping| #![auto]
156 sub.contains(m) && sub.contains(n) && m != n implies
157 m.va_range.end <= n.va_range.start || n.va_range.end <= m.va_range.start by {};
158}
159
160pub proof fn lemma_wf_union(a: Set<Mapping>, b: Set<Mapping>)
162 requires
163 wf_mapping_set(a),
164 wf_mapping_set(b),
165 forall|m: Mapping, n: Mapping|
166 #[trigger] a.contains(m) && #[trigger] b.contains(n) ==>
167 m.va_range.end <= n.va_range.start || n.va_range.end <= m.va_range.start,
168 ensures
169 wf_mapping_set(a.union(b)),
170{
171 vstd::set::axiom_set_union_finite(a, b);
172 assert forall|m: Mapping| #![auto] a.union(b).contains(m) implies m.inv() by {};
173 assert forall|m: Mapping, n: Mapping| #![auto]
174 a.union(b).contains(m) && a.union(b).contains(n) && m != n implies
175 m.va_range.end <= n.va_range.start || n.va_range.end <= m.va_range.start by {};
176}
177
178pub proof fn lemma_sub_mapping_pa_compose(m: Mapping, p: Mapping, orig: Mapping)
181 requires
182 m.inv(),
183 orig.inv(),
184 p.va_range.start >= orig.va_range.start,
185 p.va_range.end <= orig.va_range.end,
186 p.pa_range.start == (orig.pa_range.start + (p.va_range.start - orig.va_range.start)) as usize,
187 p.property == orig.property,
188 m.va_range.start >= p.va_range.start,
189 m.va_range.end <= p.va_range.end,
190 m.pa_range.start == (p.pa_range.start + (m.va_range.start - p.va_range.start)) as usize,
191 m.property == p.property,
192 ensures
193 orig.va_range.start <= m.va_range.start,
194 m.va_range.end <= orig.va_range.end,
195 m.pa_range.start == (orig.pa_range.start + (m.va_range.start - orig.va_range.start)) as usize,
196 m.property == orig.property,
197{
198 assert(MAX_PADDR < usize::MAX) by (compute_only);
199 assert(p.va_range.start - orig.va_range.start <= orig.page_size);
201 assert(m.va_range.start - orig.va_range.start <= orig.page_size);
202 assert(orig.pa_range.start + (p.va_range.start - orig.va_range.start) < usize::MAX);
203 assert(p.pa_range.start as int == orig.pa_range.start as int + (p.va_range.start as int - orig.va_range.start as int));
204 assert(orig.pa_range.start + (m.va_range.start - orig.va_range.start) < usize::MAX);
205 assert(p.pa_range.start + (m.va_range.start - p.va_range.start) < usize::MAX);
206 assert(m.pa_range.start as int == p.pa_range.start as int + (m.va_range.start as int - p.va_range.start as int));
207 assert(m.pa_range.start as int == orig.pa_range.start as int + (m.va_range.start as int - orig.va_range.start as int));
208}
209
210}