Skip to content

Commit 4fcc240

Browse files
authored
Prove admit() related to va level (#70)
* Prove `lemma_va_range_get_guard_level` * Prove `lemma_va_range_get_tree_path` * Prove `lemma_is_child_level_relation` * Prove `lemma_va_level_to_nid_inc`
1 parent ca8ef69 commit 4fcc240

3 files changed

Lines changed: 159 additions & 4 deletions

File tree

lock-protocol/src/exec/rw/common.rs

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,123 @@ pub proof fn lemma_va_level_to_nid_inc(va: Vaddr, level: PagingLevel, nid: NodeI
135135
ensures
136136
NodeHelper::get_child(nid, idx) == va_level_to_nid(va, level),
137137
{
138-
admit(); // TODO
138+
// Establish the relationship between traces at consecutive levels
139+
let trace_level_plus_1 = va_level_to_trace(va, (level + 1) as PagingLevel);
140+
let trace_level = va_level_to_trace(va, level);
141+
142+
// Show that trace_level = trace_level_plus_1.push(idx)
143+
assert(trace_level == trace_level_plus_1.push(idx)) by {
144+
// By definition: va_level_to_trace(va, level) = va_level_to_trace_rec(va >> 12, level)
145+
// And: va_level_to_trace_rec(va >> 12, level) = va_level_to_trace_rec(va >> 12, level + 1).push(((va >> 12 >> (level * 9)) & mask) as nat)
146+
// We need to show that ((va >> 12 >> (level * 9)) & mask) as nat == idx
147+
// Since idx = va_level_to_offset(va, level + 1) = ((va >> (12 + level * 9)) & mask) as nat
148+
// And (va >> 12 >> (level * 9)) = (va >> (12 + level * 9)) by bit shift properties
149+
// reveal(va_level_to_trace_rec);
150+
assert(va_level_to_trace_rec(va >> 12, level) == va_level_to_trace_rec(
151+
va >> 12,
152+
(level + 1) as PagingLevel,
153+
).push(((va >> 12 >> (level * 9)) & low_bits_mask(9) as usize) as nat));
154+
155+
// Show the bit extraction equivalence
156+
let offset = (va >> 12 >> (level * 9)) & low_bits_mask(9) as usize;
157+
assert(offset as nat == idx) by {
158+
// va_level_to_offset(va, level + 1) = ((va >> (12 + ((level + 1) - 1) * 9)) & mask) as nat
159+
// = ((va >> (12 + level * 9)) & mask) as nat
160+
// We need to show: (va >> 12 >> (level * 9)) & mask == (va >> (12 + level * 9)) & mask
161+
// This follows from bit shift associativity: a >> b >> c == a >> (b + c)
162+
assert(low_bits_mask(9) == 511) by {
163+
lemma_low_bits_mask_values();
164+
};
165+
assert((va >> 12 >> (level * 9)) == (va >> (12 + level * 9))) by (bit_vector);
166+
assert(((va >> 12 >> (level * 9)) & 511 as usize) == ((va >> (12 + level * 9))
167+
& 511 as usize)) by (bit_vector);
168+
}
169+
};
170+
171+
// Now use the fact that nid = trace_to_nid(trace_level_plus_1)
172+
// and get_child(nid, idx) = trace_to_nid(nid_to_trace(nid).push(idx))
173+
assert(NodeHelper::nid_to_trace(nid) == trace_level_plus_1) by {
174+
// First establish that trace_level_plus_1 is a valid trace
175+
assert(NodeHelper::valid_trace(trace_level_plus_1)) by {
176+
// trace_level_plus_1 = va_level_to_trace(va, level + 1)
177+
// Use the lemma that directly proves va_level_to_trace produces valid traces
178+
lemma_va_level_to_trace_valid(va, (level + 1) as PagingLevel);
179+
};
180+
181+
// Since nid = trace_to_nid(trace_level_plus_1) and trace_to_nid is bijective
182+
NodeHelper::lemma_nid_to_trace_sound(nid);
183+
NodeHelper::lemma_trace_to_nid_sound(trace_level_plus_1);
184+
// From the precondition: nid == va_level_to_nid(va, level + 1)
185+
// And va_level_to_nid(va, level + 1) == trace_to_nid(trace_level_plus_1)
186+
// So nid == trace_to_nid(trace_level_plus_1)
187+
// Since trace_to_nid is bijective, nid_to_trace(nid) == trace_level_plus_1
188+
assert(nid == NodeHelper::trace_to_nid(trace_level_plus_1));
189+
assert(NodeHelper::trace_to_nid(NodeHelper::nid_to_trace(nid)) == nid);
190+
assert(NodeHelper::trace_to_nid(NodeHelper::nid_to_trace(nid)) == NodeHelper::trace_to_nid(
191+
trace_level_plus_1,
192+
));
193+
NodeHelper::lemma_trace_to_nid_bijective();
194+
};
195+
196+
// Therefore get_child(nid, idx) = trace_to_nid(trace_level_plus_1.push(idx)) = trace_to_nid(trace_level)
197+
assert(NodeHelper::get_child(nid, idx) == NodeHelper::trace_to_nid(
198+
trace_level_plus_1.push(idx),
199+
));
200+
assert(trace_level_plus_1.push(idx) == trace_level);
201+
assert(NodeHelper::get_child(nid, idx) == NodeHelper::trace_to_nid(trace_level));
202+
assert(NodeHelper::trace_to_nid(trace_level) == va_level_to_nid(va, level));
203+
}
204+
205+
pub proof fn lemma_va_level_to_trace_rec_len(va: Vaddr, level: PagingLevel)
206+
requires
207+
1 <= level <= 4,
208+
ensures
209+
va_level_to_trace_rec(va, level).len() == 4 - level,
210+
decreases 4 - level,
211+
{
212+
if level < 4 {
213+
lemma_va_level_to_trace_rec_len(va, (level + 1) as PagingLevel);
214+
}
215+
}
216+
217+
pub proof fn lemma_va_level_to_trace_valid(va: Vaddr, level: PagingLevel)
218+
requires
219+
1 <= level <= 4,
220+
ensures
221+
NodeHelper::valid_trace(va_level_to_trace(va, level)),
222+
{
223+
lemma_va_level_to_trace_rec_valid(va >> 12, level);
224+
}
225+
226+
pub proof fn lemma_va_level_to_trace_rec_valid(va: Vaddr, level: PagingLevel)
227+
requires
228+
1 <= level <= 4,
229+
ensures
230+
NodeHelper::valid_trace(va_level_to_trace_rec(va, level)),
231+
decreases 4 - level,
232+
{
233+
if level < 4 {
234+
lemma_va_level_to_trace_rec_valid(va, (level + 1) as PagingLevel);
235+
let offset = (va >> (level * 9)) & low_bits_mask(9) as usize;
236+
assert(offset < 512) by {
237+
assert(low_bits_mask(9) == 511) by {
238+
lemma_low_bits_mask_values();
239+
};
240+
assert((va >> (level * 9)) & 511 <= 511) by (bit_vector);
241+
}
242+
// By inductive hypothesis, the recursive trace is valid
243+
assert(NodeHelper::valid_trace(va_level_to_trace_rec(va, (level + 1) as PagingLevel)));
244+
// Therefore its length is < 4
245+
assert(va_level_to_trace_rec(va, (level + 1) as PagingLevel).len() < 4);
246+
// Since we add exactly one element, the new length is still < 4
247+
assert(va_level_to_trace_rec(va, level).len() == va_level_to_trace_rec(
248+
va,
249+
(level + 1) as PagingLevel,
250+
).len() + 1);
251+
assert(va_level_to_trace_rec(va, (level + 1) as PagingLevel).len() + 1 <= 3) by {
252+
lemma_va_level_to_trace_rec_len(va, (level + 1) as PagingLevel);
253+
};
254+
}
139255
}
140256

141257
} // verus!

lock-protocol/src/exec/rw/cursor.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use builtin::*;
66
use builtin_macros::*;
77
use vstd::prelude::*;
88
use vstd::atomic_with_ghost;
9+
use vstd::bits::*;
910
use vstd::rwlock::{ReadHandle, WriteHandle};
1011
use vstd::vpanic;
1112
use vstd::pervasive::allow_panic;
@@ -162,13 +163,30 @@ pub open spec fn va_range_get_guard_level(va: Range<Vaddr>) -> PagingLevel
162163
va_range_get_guard_level_rec(va, 4)
163164
}
164165

166+
pub proof fn lemma_va_range_get_guard_level_rec(va: Range<Vaddr>, level: PagingLevel)
167+
requires
168+
va_range_wf(va),
169+
1 <= level <= 4,
170+
ensures
171+
1 <= va_range_get_guard_level_rec(va, level) <= level,
172+
decreases level,
173+
{
174+
if level > 1 {
175+
let st = va.start;
176+
let en = (va.end - 1) as usize;
177+
if va_level_to_offset(st, level) == va_level_to_offset(en, level) {
178+
lemma_va_range_get_guard_level_rec(va, (level - 1) as PagingLevel);
179+
}
180+
}
181+
}
182+
165183
pub proof fn lemma_va_range_get_guard_level(va: Range<Vaddr>)
166184
requires
167185
va_range_wf(va),
168186
ensures
169187
1 <= va_range_get_guard_level(va) <= 4,
170188
{
171-
admit(); // TODO
189+
lemma_va_range_get_guard_level_rec(va, 4);
172190
}
173191

174192
pub open spec fn va_range_get_tree_path(va: Range<Vaddr>) -> Seq<NodeId>
@@ -191,7 +209,26 @@ pub proof fn lemma_va_range_get_tree_path(va: Range<Vaddr>)
191209
),
192210
va_range_get_tree_path(va).len() == 5 - va_range_get_guard_level(va),
193211
{
194-
admit(); //TODO
212+
let guard_level = va_range_get_guard_level(va);
213+
let trace = va_level_to_trace(va.start, guard_level);
214+
lemma_va_range_get_guard_level(va);
215+
lemma_va_level_to_trace_rec_len(va.start >> 12, guard_level);
216+
assert(trace.len() == 4 - guard_level);
217+
let path = va_range_get_tree_path(va);
218+
assert(path.len() == 1 + trace.len());
219+
assert(path.len() == 5 - guard_level);
220+
assert forall|i| 0 <= i < path.len() implies NodeHelper::valid_nid(path[i]) by {
221+
let nid = path[i];
222+
if i == 0 {
223+
assert(nid == NodeHelper::root_id());
224+
NodeHelper::lemma_root_id();
225+
} else {
226+
let sub_trace = trace.subrange(0, i);
227+
assert(nid == NodeHelper::trace_to_nid(sub_trace));
228+
lemma_va_level_to_trace_valid(va.start, guard_level);
229+
NodeHelper::lemma_trace_to_nid_sound(sub_trace);
230+
}
231+
}
195232
}
196233

197234
// pub proof fn lemma_va_range_get_tree_path_inc(

lock-protocol/src/spec/utils.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,9 @@ impl NodeHelper {
16531653
ensures
16541654
Self::nid_to_level(pa) == Self::nid_to_level(ch) + 1,
16551655
{
1656-
admit(); // TODO
1656+
Self::lemma_is_child_implies_in_subtree(pa, ch);
1657+
Self::lemma_level_dep_relation(pa);
1658+
Self::lemma_level_dep_relation(ch);
16571659
}
16581660
}
16591661

0 commit comments

Comments
 (0)