Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3574feb
fix unverified code
hiroki-chen Jun 16, 2026
a82a3d1
prove: 7 page table config axioms and rename to `lemma_`
Marsman1996 Jun 16, 2026
f259d2b
prove: 5 freshness axioms via pigeonhole over finite Set<int>
Marsman1996 Jun 16, 2026
90b76d6
prove: axiom_leading_bits_bounded via trait method
Marsman1996 Jun 16, 2026
e4dee5c
Merge remote-tracking branch 'origin/main' into fix-axiom
Marsman1996 Jun 16, 2026
aad431b
Merge branch 'pr-530' into paging-const
rikosellic Jun 16, 2026
e6c4294
Move `lemma_nr_subpage_per_huge_eq_nr_entries` into `specs/arch``
rikosellic Jun 16, 2026
c28b7fd
Move `lemma_finite_int_set_has` into `vstd_extra`
rikosellic Jun 16, 2026
221d28d
decouple hard-coded constants in `PagingConstsTrait`, but add admits
rikosellic Jun 16, 2026
e6b6665
Move `lemma_nr_subpage_per_huge_bounded` into `specs``
rikosellic Jun 16, 2026
a452e96
fix admit in `pte_index_bit_offset`
rikosellic Jun 16, 2026
f53a590
Simplify
rikosellic Jun 16, 2026
17e7085
Minor
rikosellic Jun 16, 2026
824cd5d
Fix hardcoded `CursorOwner` invariants
rikosellic Jun 17, 2026
ecb50ba
more corrections
rikosellic Jun 17, 2026
de67cb3
Minor
rikosellic Jun 17, 2026
56c0b0f
minor
rikosellic Jun 17, 2026
26e1ec9
Merge remote-tracking branch 'upstream/main' into paging-const
rikosellic Jun 17, 2026
f51832b
Make `AbstractVaddr` `PagingConst` generic
rikosellic Jun 17, 2026
a357fda
fix two wrong usage
rikosellic Jun 17, 2026
c90b4a6
another fix
rikosellic Jun 17, 2026
4130e2d
fix: syntax error
Marsman1996 Jun 17, 2026
1468fdf
prove: by adding assumes for NR_LEVELS/NR_ENTRIES
Jun 19, 2026
bd8e7f8
spec: genericized from NR_ENTRIES/INC_LEVELS to nr_subpage_per_huge::…
Marsman1996 Jun 19, 2026
21f3411
Merge remote-tracking branch 'origin/main' into paging-const
Marsman1996 Jun 20, 2026
3d1adde
prove: remove more assume
Marsman1996 Jun 20, 2026
17fd6bc
prove: bridging assume
Marsman1996 Jun 20, 2026
da719f3
prove: arch-specific assume in owners
Marsman1996 Jun 20, 2026
5dbd64d
prove: PAGE_SIZE related assumes
Marsman1996 Jun 20, 2026
f51364a
prove: inv assume
Marsman1996 Jun 20, 2026
9043c13
prove: more assume and admit
Marsman1996 Jun 20, 2026
9200dd2
prove: 10 `admit()`
Marsman1996 Jun 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ $(VERIFICATION_TARGETS):
all: verify

verify:
cargo dv verify --targets $(VERIFICATION_TARGETS)
cargo dv verify --targets $(VERIFICATION_TARGETS) -- -Awarnings

fmt:
cargo dv fmt
Expand Down
257 changes: 256 additions & 1 deletion ostd/specs/arch/x86/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use crate::arch::mm::PagingConsts;
use crate::mm::kspace::FRAME_METADATA_RANGE;
use crate::mm::kspace::{LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR, paddr_to_vaddr};
use crate::mm::{Paddr, Vaddr, page_size};
use crate::mm::{
KERNEL_VADDR_RANGE, Paddr, PagingConstsTrait, Vaddr, nr_subpage_per_huge, page_size,
};
use crate::specs::mm::frame::mapping::{
META_SLOT_SIZE, lemma_meta_to_frame_soundness, meta_to_frame,
};
use crate::specs::mm::page_table::{vaddr_make, vaddr_shift_bits};
use vstd::arithmetic::power2::pow2;
use vstd::prelude::*;
use vstd_extra::prelude::*;

Expand Down Expand Up @@ -103,4 +108,254 @@ pub broadcast proof fn lemma_meta_frame_vaddr_properties(meta: Vaddr)
};
}

pub proof fn lemma_nr_subpage_per_huge_eq_nr_entries()
ensures
crate::mm::nr_subpage_per_huge::<PagingConsts>() == NR_ENTRIES,
{
assert(crate::mm::nr_subpage_per_huge::<PagingConsts>() == 4096usize / 8usize);
}

pub proof fn lemma_page_size_spec_values()
ensures
page_size::<PagingConsts>(1) == 4096,
page_size::<PagingConsts>(2) == 2097152,
page_size::<PagingConsts>(3) == 1073741824,
page_size::<PagingConsts>(4) == 549755813888,
page_size::<PagingConsts>(5) == 281474976710656,
{
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
vstd::arithmetic::power2::lemma2_to64();
vstd::arithmetic::power2::lemma2_to64_rest();
vstd::bits::lemma_usize_pow2_no_overflow(48);
}

/// Proves the concrete values of `vaddr_make` for the x86_64 paging configuration.
///
/// For any `C: PagingConstsTrait`, since all configs share
/// `BASE_PAGE_SIZE == 4096`, `nr_subpage_per_huge == 512`, and `NR_LEVELS == 4`:
/// - `vaddr_make::<C, NR_LEVELS>(0, i) == page_size::<C>(4) * i == 0x80_0000_0000 * i`
/// - `vaddr_make::<C, NR_LEVELS>(1, i) == page_size::<C>(3) * i == 0x4000_0000 * i`
/// - `vaddr_make::<C, NR_LEVELS>(2, i) == page_size::<C>(2) * i == 0x20_0000 * i`
/// - `vaddr_make::<C, NR_LEVELS>(3, i) == page_size::<C>(1) * i == 0x1000 * i`
pub proof fn lemma_vaddr_make_values<C: PagingConstsTrait>(idx: int, i: usize)
requires
0 <= idx <= 3,
i < NR_ENTRIES,
ensures
idx == 0 ==> vaddr_make::<C, NR_LEVELS>(idx, i) == 0x80_0000_0000usize * i,
idx == 1 ==> vaddr_make::<C, NR_LEVELS>(idx, i) == 0x4000_0000usize * i,
idx == 2 ==> vaddr_make::<C, NR_LEVELS>(idx, i) == 0x20_0000usize * i,
idx == 3 ==> vaddr_make::<C, NR_LEVELS>(idx, i) == 0x1000usize * i,
{
C::lemma_paging_consts_properties();
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
vstd::arithmetic::power2::lemma2_to64();
vstd::arithmetic::power2::lemma2_to64_rest();
// After the above lemmas:
// C::BASE_PAGE_SIZE() == 4096, (4096usize).ilog2() == 12
// nr_subpage_per_huge::<C>() == 512, (512usize).ilog2() == 9
// NR_LEVELS == 4
// So vaddr_shift_bits::<C, NR_LEVELS>(idx) = (12 + 9 * (3 - idx)) as nat
// idx=0: 39, idx=1: 30, idx=2: 21, idx=3: 12
// And pow2(39) == 0x8000000000, pow2(30) == 0x40000000,
// pow2(21) == 0x200000, pow2(12) == 0x1000
// vaddr_make(idx, i) = (pow2(shift_bits) as usize * i) as usize
if idx == 0 {
assert(vaddr_shift_bits::<C, NR_LEVELS>(0) == 39nat);
assert(pow2(39) == 0x8000000000int);
assert(vaddr_make::<C, NR_LEVELS>(0, i) == (0x8000000000int * i as int) as usize);
assert(0x80_0000_0000usize * i == (0x8000000000int * i as int) as usize)
by (nonlinear_arith)
requires
i < 512,
;
} else if idx == 1 {
assert(vaddr_shift_bits::<C, NR_LEVELS>(1) == 30nat);
assert(pow2(30) == 0x40000000int);
assert(vaddr_make::<C, NR_LEVELS>(1, i) == (0x40000000int * i as int) as usize);
assert(0x4000_0000usize * i == (0x40000000int * i as int) as usize) by (nonlinear_arith)
requires
i < 512,
;
} else if idx == 2 {
assert(vaddr_shift_bits::<C, NR_LEVELS>(2) == 21nat);
assert(pow2(21) == 0x200000int);
assert(vaddr_make::<C, NR_LEVELS>(2, i) == (0x200000int * i as int) as usize);
assert(0x20_0000usize * i == (0x200000int * i as int) as usize) by (nonlinear_arith)
requires
i < 512,
;
} else {
assert(idx == 3);
assert(vaddr_shift_bits::<C, NR_LEVELS>(3) == 12nat);
assert(pow2(12) == 0x1000int);
assert(vaddr_make::<C, NR_LEVELS>(3, i) == (0x1000int * i as int) as usize);
assert(0x1000usize * i == (0x1000int * i as int) as usize) by (nonlinear_arith)
requires
i < 512,
;
}
}

/// Proves `page_size` values for any `C: PagingConstsTrait`. All configs share
/// `BASE_PAGE_SIZE == 4096` and `nr_subpage_per_huge == 512`, so page sizes are fixed.
pub proof fn lemma_page_size_values<C: PagingConstsTrait>()
ensures
page_size::<C>(1) == 0x1000usize,
page_size::<C>(2) == 0x20_0000usize,
page_size::<C>(3) == 0x4000_0000usize,
page_size::<C>(4) == 0x80_0000_0000usize,
page_size::<C>(5) == 0x1_0000_0000_0000usize,
{
C::lemma_paging_consts_properties();
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
vstd::arithmetic::power2::lemma2_to64();
vstd::arithmetic::power2::lemma2_to64_rest();
vstd::bits::lemma_usize_pow2_no_overflow(48);
}

/// Arch-specific arithmetic step for `AbstractVaddr::from_vaddr_to_vaddr_roundtrip`.
/// Proves the 64-bit positional decomposition identity for any 64-bit `va`,
/// using the x86_64 layout (12-bit offset, 4 × 9-bit indices, 16-bit leading bits).
pub proof fn lemma_from_vaddr_to_vaddr_roundtrip<C: PagingConstsTrait>(va: crate::mm::Vaddr)
ensures
crate::specs::mm::page_table::AbstractVaddr::<C>::from_vaddr(va).to_vaddr() == va,
{
use crate::specs::mm::page_table::AbstractVaddr;
C::lemma_paging_consts_properties();
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
vstd::arithmetic::power2::lemma2_to64();
vstd::arithmetic::power2::lemma2_to64_rest();
let abs = AbstractVaddr::<C>::from_vaddr(va);
assert(abs.to_vaddr_indices(NR_LEVELS as int) == 0);
assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) as int + abs.to_vaddr_indices(4));
assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) as int + abs.to_vaddr_indices(3));
assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) as int + abs.to_vaddr_indices(2));
assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) as int + abs.to_vaddr_indices(1));
assert(va == (va % 4096usize) + ((va / 4096usize) % 512usize) * 4096usize + ((va
/ 0x20_0000usize) % 512usize) * 0x20_0000usize + ((va / 0x4000_0000usize) % 512usize)
* 0x4000_0000usize + ((va / 0x80_0000_0000usize) % 512usize) * 0x80_0000_0000usize + (va
/ 0x1_0000_0000_0000usize) * 0x1_0000_0000_0000usize) by (bit_vector);
}

/// Arch-specific arithmetic step for `AbstractVaddr::to_vaddr_from_vaddr_roundtrip`.
/// Proves that reconstructing a 64-bit `va` from a well-formed `AbstractVaddr`
/// and extracting its components yields the same `AbstractVaddr`, using the
/// x86_64 layout (12-bit offset, 4 × 9-bit indices, 16-bit leading bits).
pub proof fn lemma_to_vaddr_from_vaddr_roundtrip<C: PagingConstsTrait>(
abs: crate::specs::mm::page_table::AbstractVaddr<C>,
)
requires
abs.inv(),
ensures
crate::specs::mm::page_table::AbstractVaddr::<C>::from_vaddr(abs.to_vaddr()) == abs,
{
use crate::specs::mm::page_table::AbstractVaddr;
C::lemma_paging_consts_properties();
vstd_extra::external::ilog2::lemma_usize_ilog2_to32();
vstd::arithmetic::power2::lemma2_to64();
vstd::arithmetic::power2::lemma2_to64_rest();
abs.to_vaddr_bounded();
assert(abs.to_vaddr_indices(NR_LEVELS as int) == 0);
assert(abs.to_vaddr_indices(3) == abs.index[3] * pow2(39nat) as int + abs.to_vaddr_indices(4));
assert(abs.to_vaddr_indices(2) == abs.index[2] * pow2(30nat) as int + abs.to_vaddr_indices(3));
assert(abs.to_vaddr_indices(1) == abs.index[1] * pow2(21nat) as int + abs.to_vaddr_indices(2));
assert(abs.to_vaddr_indices(0) == abs.index[0] * pow2(12nat) as int + abs.to_vaddr_indices(1));

assert(abs.index.contains_key(0));
assert(abs.index.contains_key(1));
assert(abs.index.contains_key(2));
assert(abs.index.contains_key(3));
let i0 = abs.index[0] as usize;
let i1 = abs.index[1] as usize;
let i2 = abs.index[2] as usize;
let i3 = abs.index[3] as usize;
let o = abs.offset as usize;
let tb = abs.leading_bits as usize;
let va = abs.to_vaddr();
assert(i0 < 512usize);
assert(i1 < 512usize);
assert(i2 < 512usize);
assert(i3 < 512usize);
assert(va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize);

assert(va % 4096usize == o) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;
assert((va / 4096usize) % 512usize == i0) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;
assert((va / 0x20_0000usize) % 512usize == i1) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;
assert((va / 0x4000_0000usize) % 512usize == i2) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;
assert((va / 0x80_0000_0000usize) % 512usize == i3) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;
assert(va / 0x1_0000_0000_0000usize == tb) by (bit_vector)
requires
va == o + i0 * 4096usize + i1 * 0x20_0000usize + i2 * 0x4000_0000usize + i3
* 0x80_0000_0000usize + tb * 0x1_0000_0000_0000usize,
o < 4096usize,
i0 < 512usize,
i1 < 512usize,
i2 < 512usize,
i3 < 512usize,
tb < 0x1_0000usize,
;

let back = AbstractVaddr::<C>::from_vaddr(va);
assert forall|i: int| 0 <= i < NR_LEVELS implies #[trigger] back.index[i] == abs.index[i] by {
if i == 0 {
} else if i == 1 {
} else if i == 2 {
} else if i == 3 {
}
}
assert(back.index == abs.index);
}

} // verus!
2 changes: 1 addition & 1 deletion ostd/specs/mm/embedding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ use core::ops::Range;

use vstd::prelude::*;
use vstd_extra::ownership::*;
use vstd_extra::set_extra::*;
use vstd_extra::prelude::*;

use crate::mm::frame::{MetaSlot, UFrame};
use crate::mm::page_prop::PageProperty;
Expand Down
27 changes: 26 additions & 1 deletion ostd/specs/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ pub mod page_table;
pub mod tlb;
pub mod virt_mem;

use vstd::arithmetic::div_mod::group_div_basics;
use vstd::arithmetic::div_mod::lemma_div_non_zero;
use vstd::prelude::*;

use vstd_extra::ownership::*;

use crate::mm::vm_space::UserPtConfig;
use crate::mm::{Paddr, Vaddr};
use crate::mm::{KERNEL_VADDR_RANGE, Paddr, PagingConstsTrait, Vaddr, nr_subpage_per_huge};
use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
use crate::specs::mm::page_table::{Guards, INC_LEVELS, Mapping, PageTableOwner, PageTableView};
use crate::specs::mm::tlb::TlbModel;
Expand Down Expand Up @@ -135,4 +137,27 @@ impl GlobalMemOwner {
}
}

pub proof fn lemma_nr_subpage_per_huge_bounded<C: PagingConstsTrait>()
ensures
0 < nr_subpage_per_huge::<C>() <= C::BASE_PAGE_SIZE(),
{
C::lemma_paging_consts_requirements();
broadcast use group_div_basics;

assert(C::BASE_PAGE_SIZE() / C::PTE_SIZE() > 0) by {
lemma_div_non_zero(C::BASE_PAGE_SIZE() as int, C::PTE_SIZE() as int);
};
}

/// For any VA within the kernel virtual address range and any page level,
/// va + page_size(level) does not overflow usize.
pub proof fn lemma_va_plus_page_size_no_overflow(va: Vaddr, len: usize)
requires
va + len <= KERNEL_VADDR_RANGE.end,
ensures
va + len <= usize::MAX,
{
assert(KERNEL_VADDR_RANGE.end == 0xffff_ffff_ffff_0000usize) by (compute_only);
}

} // verus!
Loading