Skip to content

Commit 21f3411

Browse files
Marsman1996claude
andcommitted
Merge remote-tracking branch 'origin/main' into paging-const
Resolved conflicts between paging-const genericization and upstream changes (PRs asterinas#531, asterinas#534, asterinas#537). Adapted upstream's new proven proofs to use generic C::NR_LEVELS()/nr_subpage_per_huge::<C>() forms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2 parents bd8e7f8 + 856819e commit 21f3411

26 files changed

Lines changed: 644 additions & 302 deletions

File tree

ostd/specs/mm/page_table/cursor/cursor_fn_lemmas.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use vstd_extra::arithmetic::{
1717
lemma_nat_align_up_sound,
1818
};
1919

20+
use crate::arch::mm::PagingConsts;
2021
use crate::mm::nr_subpage_per_huge;
2122
use crate::mm::page_table::*;
2223
use crate::mm::{PagingConstsTrait, PagingLevel, Vaddr, page_size};
@@ -334,7 +335,93 @@ impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
334335
self.continuations[j].path().index(self.continuations[i].path().len() as int)
335336
== self.continuations[i].idx,
336337
{
337-
admit();
338+
C::lemma_paging_consts_properties();
339+
assert(nr_subpage_per_huge::<C>() == NR_ENTRIES);
340+
// Explicitly instantiate continuation invariants for all indices
341+
// that the case branches use. inv_continuation(k) requires
342+
// self.level - 1 <= k <= C::NR_LEVELS() - 1, which holds for
343+
// all k in [j, i] since self.level - 1 <= j < i < C::NR_LEVELS().
344+
self.inv_continuation(i);
345+
self.inv_continuation(j);
346+
// Also instantiate for intermediate indices used in the i==3,j==0
347+
// and i==2,j==0 branches (they access continuations[1] and [2]).
348+
if j < i - 1 {
349+
// There's at least one index between j and i
350+
self.inv_continuation(j + 1);
351+
if j + 2 < i {
352+
self.inv_continuation(j + 2);
353+
}
354+
}
355+
if i == 3 && j == 2 {
356+
self.continuations[3].path().push_tail_property_index(
357+
self.continuations[3].idx as usize,
358+
);
359+
self.continuations[3].path().push_tail_property_len(self.continuations[3].idx as usize);
360+
} else if i == 3 && j == 1 {
361+
let p3 = self.continuations[3].path();
362+
let p2 = self.continuations[2].path();
363+
let idx3 = self.continuations[3].idx as usize;
364+
let idx2 = self.continuations[2].idx as usize;
365+
p3.push_tail_property_index(idx3);
366+
p3.push_tail_property_len(idx3);
367+
p2.push_tail_property_index(idx2);
368+
p2.push_tail_property_len(idx2);
369+
assert(p3.len() < p2.len());
370+
assert(self.continuations[1].path() == p2.push_tail(idx2));
371+
assert(p2.push_tail(idx2).index(p3.len() as int) == p2.index(p3.len() as int));
372+
} else if i == 3 && j == 0 {
373+
let p3 = self.continuations[3].path();
374+
let p2 = self.continuations[2].path();
375+
let p1 = self.continuations[1].path();
376+
let idx3 = self.continuations[3].idx as usize;
377+
let idx2 = self.continuations[2].idx as usize;
378+
let idx1 = self.continuations[1].idx as usize;
379+
p3.push_tail_property_index(idx3);
380+
p3.push_tail_property_len(idx3);
381+
p2.push_tail_property_index(idx2);
382+
p2.push_tail_property_len(idx2);
383+
p1.push_tail_property_index(idx1);
384+
p1.push_tail_property_len(idx1);
385+
assert(p3.len() < p2.len());
386+
assert(p3.len() < p1.len());
387+
assert(p1.push_tail(idx1).index(p3.len() as int) == p1.index(p3.len() as int));
388+
assert(p2.push_tail(idx2).index(p3.len() as int) == p2.index(p3.len() as int));
389+
} else if i == 2 && j == 1 {
390+
self.continuations[2].path().push_tail_property_index(
391+
self.continuations[2].idx as usize,
392+
);
393+
self.continuations[2].path().push_tail_property_len(self.continuations[2].idx as usize);
394+
} else if i == 2 && j == 0 {
395+
let p2 = self.continuations[2].path();
396+
let p1 = self.continuations[1].path();
397+
let idx2 = self.continuations[2].idx as usize;
398+
let idx1 = self.continuations[1].idx as usize;
399+
p2.push_tail_property_index(idx2);
400+
p2.push_tail_property_len(idx2);
401+
p1.push_tail_property_index(idx1);
402+
p1.push_tail_property_len(idx1);
403+
assert(p2.len() < p1.len());
404+
assert(self.continuations[0].path() == p1.push_tail(idx1));
405+
assert(p1.push_tail(idx1).index(p2.len() as int) == p1.index(p2.len() as int));
406+
assert(p1 == p2.push_tail(idx2));
407+
assert(p2.push_tail(idx2).index(p2.len() as int) == idx2);
408+
} else if i == 1 && j == 0 {
409+
self.continuations[1].path().push_tail_property_index(
410+
self.continuations[1].idx as usize,
411+
);
412+
self.continuations[1].path().push_tail_property_len(self.continuations[1].idx as usize);
413+
}
414+
}
415+
416+
pub proof fn lemma_page_size_spec_5_eq_pow2_48()
417+
ensures
418+
page_size::<PagingConsts>(5) == pow2(48nat) as usize,
419+
{
420+
crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
421+
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
422+
vstd::arithmetic::power2::lemma2_to64();
423+
vstd::arithmetic::power2::lemma2_to64_rest();
424+
vstd::arithmetic::power2::lemma_pow2_adds(12nat, 36nat);
338425
}
339426

340427
pub proof fn jump_not_in_node_level_lt_guard_minus_one(

ostd/specs/mm/page_table/cursor/cursor_steps.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,9 @@ impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
15581558
self.pop_level_owner().0.only_current_locked(guards),
15591559
self.pop_level_owner().0.nodes_locked(guards),
15601560
self.pop_level_owner().0.metaregion_sound(regions),
1561+
self.pop_level_owner().0.cur_entry_owner().is_node(),
1562+
self.pop_level_owner().1.inner.inner@.ptr.addr()
1563+
== self.pop_level_owner().0.cur_entry_owner().node().meta_addr_self(),
15611564
{
15621565
assume(nr_subpage_per_huge::<C>() == NR_ENTRIES);
15631566
self.inv_continuation(self.level - 1);
@@ -1648,6 +1651,29 @@ impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
16481651
}
16491652
};
16501653
};
1654+
1655+
// The cur_entry_owner of the popped owner is the child entry we just
1656+
// restored: new_cont.children[new_cont.idx] == Some(child_node)
1657+
// where child_node.value == child.entry_own, which is a node
1658+
// (from child.inv() => child.entry_own.is_node()).
1659+
assert(child.inv());
1660+
assert(child.entry_own.is_node());
1661+
assert(new_cont.idx == cont.idx);
1662+
assert(new_cont.children[new_cont.idx as int] == Some(child_node));
1663+
assert(child_node.value == child.entry_own);
1664+
// new_owner.level == self.level + 1
1665+
// new_owner.continuations[new_owner.level - 1] == new_cont
1666+
assert(new_owner.level == (self.level + 1) as u8);
1667+
assert(new_owner.continuations[new_owner.level as int - 1] == new_cont);
1668+
assert(new_owner.cur_entry_owner() == child.entry_own);
1669+
assert(new_owner.cur_entry_owner().is_node());
1670+
// The guard returned by pop_level_owner is child.guard (from restore).
1671+
// child.inv() gives relate_guard, so guard.addr == cur_entry_owner().node().meta_addr_self().
1672+
let (_new_owner, pop_guard) = self.pop_level_owner();
1673+
assert(pop_guard == child.guard);
1674+
assert(child.entry_own.node().relate_guard(child.guard));
1675+
assert(pop_guard.inner.inner@.ptr.addr()
1676+
== new_owner.cur_entry_owner().node().meta_addr_self());
16511677
}
16521678

16531679
/// Update va to a new value that shares the same indices at levels >= self.level.

ostd/specs/mm/page_table/cursor/owners.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,8 @@ impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
941941
C::lemma_nr_subpage_per_huge_eq_nr_entries();
942942
assume(C::BASE_PAGE_SIZE() == PAGE_SIZE);
943943
C::lemma_paging_consts_requirements();
944+
C::lemma_paging_consts_properties();
945+
assert(nr_subpage_per_huge::<C>() == NR_ENTRIES);
944946
self.popped_too_high = false;
945947
let tracked mut cont = self.continuations.tracked_remove(self.level - 1);
946948
cont.do_inc_index();
@@ -2069,6 +2071,7 @@ impl<'rcu, C: PageTableConfig> CursorOwner<'rcu, C> {
20692071
let big = 0x1_0000_0000_0000int; // 2^48 == page_size(NR_LEVELS+1)
20702072
let ps_nr = page_size::<C>(C::NR_LEVELS() as PagingLevel) as int;
20712073

2074+
crate::specs::arch::lemma_page_size_spec_values();
20722075
// node_size == page_size_spec(5) == 2^48; page_size(NR_LEVELS) == 2^39 < 2^48.
20732076

20742077
// ---- prefix.to_vaddr() == lb * 2^48 -------------------------------

ostd/specs/mm/page_table/cursor/page_size_lemmas.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use vstd::arithmetic::power2::pow2;
22
use vstd::prelude::*;
33

44
use crate::arch::mm::PagingConsts;
5-
use crate::mm::{Paddr, Vaddr, nr_subpage_per_huge, page_size};
6-
use crate::mm::{PagingConstsTrait, PagingLevel};
7-
use crate::specs::arch::*;
5+
use crate::mm::PagingLevel;
6+
use crate::mm::{KERNEL_VADDR_RANGE, MAX_PADDR, Paddr, Vaddr, nr_subpage_per_huge, page_size};
7+
use crate::mm::PagingConstsTrait;
8+
use crate::specs::arch::{NR_LEVELS, PAGE_SIZE};
89

910
verus! {
1011

12+
// ─── page_size(1) ──────────────────────────────────────────────────────
1113
/// page_size::<C>(1) == C::BASE_PAGE_SIZE.
1214
pub proof fn lemma_page_size_spec_level1<C: PagingConstsTrait>()
1315
ensures
@@ -22,8 +24,9 @@ pub proof fn lemma_page_size_spec_level1<C: PagingConstsTrait>()
2224
assume(PAGE_SIZE == C::BASE_PAGE_SIZE());
2325
}
2426

25-
/// When `va` is aligned to `page_size::<C>(large_level)` and `level <= large_level`,
26-
/// then `va` is aligned to page_size::<C>(level).
27+
// ─── VA alignment ────────────────────────────────────────────────────────────
28+
/// When `va` is aligned to `page_size::<C>(large_level)` and `level <= large_level` (so
29+
/// page_size::<C>(level) divides page_size::<C>(large_level)), then `va` is aligned to page_size::<C>(level).
2730
pub proof fn lemma_va_align_page_size<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel)
2831
requires
2932
1 <= level <= C::NR_LEVELS() + 1,
@@ -63,6 +66,8 @@ pub proof fn lemma_va_align_page_size<C: PagingConstsTrait>(va: Vaddr, level: Pa
6366
}
6467
}
6568

69+
/// Special case for level 1: page_size::<C>(1) == C::BASE_PAGE_SIZE(), so va % C::BASE_PAGE_SIZE() == 0 implies
70+
/// va % page_size::<C>(1) == 0.
6671
pub proof fn lemma_va_align_page_size_level_1<C: PagingConstsTrait>(va: Vaddr)
6772
requires
6873
va % C::BASE_PAGE_SIZE() == 0,

ostd/specs/mm/page_table/mod.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use core::marker::PhantomData;
2222

2323
use crate::mm::page_table::PageTableConfig;
2424
use crate::mm::{PagingConstsTrait, PagingLevel, Vaddr, nr_subpage_per_huge, page_size};
25+
use crate::arch::mm::PagingConsts;
2526
use crate::specs::arch::*;
2627

2728
use align_ext::AlignExt;
@@ -965,7 +966,36 @@ impl<C: PagingConstsTrait> AbstractVaddr<C> {
965966
self.rec_compute_vaddr(start) as int == self.to_vaddr_indices(start) + self.offset,
966967
decreases C::NR_LEVELS() - start,
967968
{
968-
admit();
969+
vstd::arithmetic::power2::lemma2_to64();
970+
vstd::arithmetic::power2::lemma2_to64_rest();
971+
lemma_page_size_spec_values();
972+
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
973+
C::lemma_paging_consts_properties();
974+
assert(nr_subpage_per_huge::<C>() == NR_ENTRIES);
975+
self.to_vaddr_indices_gap_bound(start);
976+
if start < C::NR_LEVELS() {
977+
self.rec_compute_vaddr_is_to_vaddr_indices(start + 1);
978+
self.to_vaddr_indices_gap_bound(start + 1);
979+
assert(self.index.contains_key(start));
980+
// page_size(start+1) matches the positional shift pow2(12 + 9*start).
981+
// For NR_LEVELS == 4, enumerate concrete cases so the constant
982+
// folds from `lemma_page_size_spec_values`.
983+
// With nr_subpage_per_huge::<C>() == NR_ENTRIES == nr_subpage_per_huge::<PagingConsts>(),
984+
// page_size::<C>(n) == page_size::<PagingConsts>(n).
985+
if start == 0 {
986+
assert(page_size::<C>(1) == page_size::<PagingConsts>(1));
987+
assert(page_size::<C>(1) == pow2(12nat) as usize);
988+
} else if start == 1 {
989+
assert(page_size::<C>(2) == page_size::<PagingConsts>(2));
990+
assert(page_size::<C>(2) == pow2(21nat) as usize);
991+
} else if start == 2 {
992+
assert(page_size::<C>(3) == page_size::<PagingConsts>(3));
993+
assert(page_size::<C>(3) == pow2(30nat) as usize);
994+
} else {
995+
assert(page_size::<C>(4) == page_size::<PagingConsts>(4));
996+
assert(page_size::<C>(4) == pow2(39nat) as usize);
997+
}
998+
}
969999
}
9701000

9711001
/// Full identity relating `to_vaddr()` to `compute_vaddr()`:

ostd/specs/mm/page_table/node/entry_owners.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,51 @@ impl<C: PageTableConfig> EntryOwner<C> {
448448
(self.parent_level - 1) as PagingLevel,
449449
)) as Paddr) % PAGE_SIZE == 0,
450450
{
451-
admit();
451+
let pa = self.frame().mapped_pa;
452+
let child_pa = (pa + idx * page_size::<C>((self.parent_level - 1) as PagingLevel)) as Paddr;
453+
C::lemma_paging_consts_properties();
454+
assert(C::NR_LEVELS() == NR_LEVELS);
455+
assert(self.parent_level == 2 || self.parent_level == 3);
456+
assert(NR_ENTRIES == 512) by {
457+
crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
458+
};
459+
assert(crate::mm::nr_subpage_per_huge::<C>() == 512usize) by {
460+
C::lemma_paging_consts_properties();
461+
};
462+
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
463+
crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_spec_level1::<C>();
464+
assert(512usize.ilog2() == 9);
465+
vstd::arithmetic::power2::lemma2_to64();
466+
if self.parent_level == 2 {
467+
assert(page_size::<C>(2) == (PAGE_SIZE * pow2((512usize.ilog2() * 1usize) as nat)) as usize);
468+
assert(page_size::<C>(2) == 2097152);
469+
assert(pa % page_size::<C>(2) == 0);
470+
crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_page_size_divides::<C>(1, 2);
471+
assert(child_pa % page_size::<C>(1) == 0);
472+
assert(child_pa + page_size::<C>(1) <= MAX_PADDR) by {
473+
assert(idx < 512);
474+
assert(idx * 4096 + 4096 <= 2097152);
475+
assert(child_pa + page_size::<C>(1) <= pa + page_size::<C>(2));
476+
};
477+
} else {
478+
assert(self.parent_level == 3);
479+
assert(page_size::<C>(3) == (PAGE_SIZE * pow2((512usize.ilog2() * 2usize) as nat)) as usize);
480+
assert(page_size::<C>(3) == 1073741824);
481+
assert(pa % page_size::<C>(3) == 0);
482+
crate::specs::mm::page_table::cursor::page_size_lemmas::lemma_va_align_page_size::<C>(pa, 2);
483+
assert(child_pa == pa + idx * page_size::<C>(2));
484+
vstd::arithmetic::div_mod::lemma_mod_multiples_basic(idx as int, page_size::<C>(2) as int);
485+
vstd::arithmetic::div_mod::lemma_add_mod_noop(
486+
pa as int,
487+
(idx * page_size::<C>(2)) as int,
488+
page_size::<C>(2) as int,
489+
);
490+
assert(child_pa % page_size::<C>(2) == 0);
491+
assert(child_pa + page_size::<C>(2) <= MAX_PADDR) by {
492+
assert(idx * 2097152 + 2097152 <= 1073741824);
493+
assert(child_pa + page_size::<C>(2) <= pa + page_size::<C>(3));
494+
};
495+
}
452496
}
453497

454498
/// Helper: sub-page validity is preserved when the only slot that changed is the

ostd/specs/mm/page_table/owners.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use vstd_extra::ownership::*;
1414
use vstd_extra::prelude::TreeNodeValue;
1515

1616
use crate::mm::{
17-
Paddr, PagingLevel, Vaddr, page_size,
17+
MAX_NR_LEVELS, Paddr, PagingConstsTrait, PagingLevel, Vaddr, page_size,
1818
page_table::{EntryOwner, EntryOwnerKind},
1919
};
2020

@@ -115,6 +115,7 @@ pub proof fn lemma_leading_bits_bounded<C: PageTableConfig>()
115115
C::lemma_leading_bits_bounded();
116116
}
117117

118+
118119
/// `vaddr(path) < 2^48` for every valid path: each term in the positional
119120
/// sum is `i_k * 2^(12 + 9·k)` with `i_k < 512 = 2^9`, so the sum is
120121
/// strictly less than `2^48`.
@@ -141,11 +142,11 @@ pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES
141142
* 0x1_0000_0000_0000int,
142143
{
143144
lemma_leading_bits_bounded::<C>();
145+
C::lemma_page_table_config_constant_requirements();
144146
lemma_vaddr_strict_bound::<C>(path);
145147
let lb = C::LEADING_BITS_spec() as int;
146148
let v = vaddr::<C>(path) as int;
147149
// `0 <= v + lb * 2^48 < 2^64`: sum fits in usize, cast is lossless.
148-
assert(0 <= v);
149150
assert(lb * 0x1_0000_0000_0000int <= 0xffff_int * 0x1_0000_0000_0000int) by (nonlinear_arith)
150151
requires
151152
lb < 0x1_0000int,
@@ -159,6 +160,37 @@ pub proof fn lemma_vaddr_of_eq_int<C: PageTableConfig>(path: TreePath<NR_ENTRIES
159160
;
160161
}
161162

163+
/// page_size is monotonically increasing in its argument.
164+
pub proof fn page_size_monotonic<C: PagingConstsTrait>(a: PagingLevel, b: PagingLevel)
165+
requires
166+
1 <= a <= b <= C::NR_LEVELS() + 1,
167+
ensures
168+
page_size::<C>(a) <= page_size::<C>(b),
169+
{
170+
if a == b {
171+
} else {
172+
let ps_a = page_size::<C>(a);
173+
let ps_b = page_size::<C>(b);
174+
175+
lemma_page_size_ge_page_size::<C>(a);
176+
lemma_page_size_ge_page_size::<C>(b);
177+
C::lemma_paging_consts_properties();
178+
179+
lemma_page_size_divides::<C>(a, b);
180+
assert(ps_b % ps_a == 0);
181+
182+
assert(ps_a <= ps_b) by {
183+
if ps_b < ps_a {
184+
vstd::arithmetic::div_mod::lemma_small_mod(ps_b as nat, ps_a as nat);
185+
assert(ps_b % ps_a == ps_b);
186+
assert(ps_b % ps_a == 0);
187+
assert(false);
188+
}
189+
}
190+
}
191+
}
192+
193+
162194
/// Sibling paths (same prefix, different last index) have disjoint VA ranges,
163195
/// separated by at least the child page size.
164196
///
@@ -1384,6 +1416,7 @@ impl<C: PageTableConfig> PageTableOwner<C> {
13841416
// Bridge `vaddr_of(path) as int == vaddr(path) + LB * 2^48`.
13851417
lemma_vaddr_of_eq_int::<C>(path);
13861418
lemma_leading_bits_bounded::<C>();
1419+
C::lemma_page_table_config_constant_requirements();
13871420
lemma_vaddr_strict_bound::<C>(path);
13881421
let lb = C::LEADING_BITS_spec() as int;
13891422
vstd::arithmetic::power2::lemma2_to64();

0 commit comments

Comments
 (0)