Skip to content

Commit 8a0a6e5

Browse files
committed
refactor: consolidate PageTableConfig proof lemmas into requirements/derived pattern
1 parent 1225d70 commit 8a0a6e5

7 files changed

Lines changed: 40 additions & 110 deletions

File tree

ostd/specs/mm/page_table/owners.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,12 @@ pub open spec fn vaddr_of<C: PageTableConfig>(path: TreePath<NR_ENTRIES>) -> usi
103103
}
104104

105105
/// Runtime bound on `LEADING_BITS_spec`: every valid config uses at most the
106-
/// 16 high bits. Proven via the `PageTableConfig::lemma_leading_bits_bounded`
107-
/// trait method that each concrete config must discharge.
106+
/// 16 high bits. Proven via `PageTableConfig::lemma_page_table_config_constant_requirements`.
108107
pub proof fn lemma_leading_bits_bounded<C: PageTableConfig>()
109108
ensures
110109
C::LEADING_BITS_spec() < 0x1_0000_usize,
111110
{
112-
C::lemma_leading_bits_bounded();
111+
C::lemma_page_table_config_constant_requirements();
113112
}
114113

115114
/// `vaddr(path) < 2^48` for every valid path: each term in the positional

ostd/specs/mm/page_table/vaddr_range_proofs.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub proof fn lemma_pt_va_range_start_shift_facts<C: PageTableConfig>(
2727
idx_start * pow2(offset as nat) <= usize::MAX,
2828
offset as nat == pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
2929
{
30-
C::lemma_top_level_index_range_bounds();
30+
C::lemma_page_table_config_constant_requirements();
3131
vstd::layout::unsigned_int_max_values();
3232

3333
let off = pte_index_bit_offset_spec::<C::C>(C::C::NR_LEVELS()) as nat;
@@ -81,7 +81,7 @@ pub proof fn lemma_pt_va_range_end_shift_facts<C: PageTableConfig>(idx_end: usiz
8181
0 < idx_end * pow2(offset as nat),
8282
offset as nat == pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
8383
{
84-
C::lemma_top_level_index_range_bounds();
84+
C::lemma_page_table_config_constant_requirements();
8585
lemma_pow2_pos(offset as nat);
8686

8787
assert(C::C::NR_LEVELS() == C::NR_LEVELS());
@@ -157,7 +157,7 @@ pub proof fn lemma_sign_bit_facts<C: PageTableConfig>(
157157
ensures
158158
(bit != 0) == ((va as int / pow2((C::ADDRESS_WIDTH() - 1) as nat) as int) % 2 == 1),
159159
{
160-
C::lemma_top_level_index_range_bounds();
160+
C::lemma_page_table_config_constant_requirements();
161161
assert(C::C::ADDRESS_WIDTH() == C::ADDRESS_WIDTH());
162162
assert(address_width == C::ADDRESS_WIDTH());
163163
assert(0 < address_width as int <= 64);
@@ -202,7 +202,7 @@ pub proof fn lemma_idx_times_pow2_bound<C: PageTableConfig>(start: Vaddr, end: V
202202
pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat,
203203
) as int) - 1,
204204
{
205-
C::lemma_top_level_index_range_bounds();
205+
C::lemma_page_table_config_constant_requirements();
206206
let off = pte_index_bit_offset_spec::<C::C>(C::C::NR_LEVELS()) as nat;
207207
let aw = C::C::ADDRESS_WIDTH() as nat;
208208
let top_w = (aw as int - off as int) as nat;
@@ -236,7 +236,7 @@ pub proof fn lemma_idx_times_pow2_bound<C: PageTableConfig>(start: Vaddr, end: V
236236
i_end <= p_top,
237237
p_off > 0,
238238
;
239-
// i_end > 0 — from `lemma_top_level_index_range_bounds`'s
239+
// i_end > 0 — from `lemma_page_table_config_constant_requirements`'s
240240
// `idx.start < idx.end` plus `idx.start >= 0` (usize).
241241
assert(i_end > 0);
242242
assert(e_pre > 0) by (nonlinear_arith)

ostd/src/mm/kspace/mod.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ unsafe impl PageTableConfig for KernelPtConfig {
167167
0xffff
168168
}
169169

170-
proof fn lemma_top_level_index_range_bounds() {
170+
proof fn lemma_page_table_config_constant_requirements() {
171171
use crate::mm::nr_subpage_per_huge;
172172
use crate::mm::page_table::{nr_pte_index_bits, pte_index_bit_offset_spec};
173173
use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds, pow2};
@@ -180,19 +180,6 @@ unsafe impl PageTableConfig for KernelPtConfig {
180180
lemma_usize_pow2_ilog2(12);
181181
lemma_usize_pow2_ilog2(9);
182182
lemma_pow2_adds(9, 39);
183-
}
184-
185-
proof fn lemma_leading_bits_only_when_high_half() {
186-
use crate::mm::nr_subpage_per_huge;
187-
use crate::mm::page_table::{nr_pte_index_bits, pte_index_bit_offset_spec};
188-
use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds, pow2};
189-
use vstd_extra::prelude::lemma_usize_pow2_ilog2;
190-
191-
lemma2_to64();
192-
lemma2_to64_rest();
193-
vstd::layout::unsigned_int_max_values();
194-
lemma_usize_pow2_ilog2(12);
195-
lemma_usize_pow2_ilog2(9);
196183
lemma_pow2_adds(8, 39);
197184
assert(nr_subpage_per_huge::<PagingConsts>() == 512_usize);
198185
assert(nr_pte_index_bits::<PagingConsts>() == 9_usize);
@@ -287,28 +274,13 @@ unsafe impl PageTableConfig for KernelPtConfig {
287274
}
288275
}
289276

290-
proof fn lemma_nr_subpage_per_huge_eq_nr_entries() {
291-
assert(Self::C::BASE_PAGE_SIZE() == 4096usize);
292-
assert(Self::C::PTE_SIZE() == 8usize);
293-
assert(crate::specs::arch::NR_ENTRIES == 512usize);
294-
}
295-
296-
proof fn lemma_leading_bits_bounded() {
297-
assert(Self::LEADING_BITS_spec() == 0xffff_usize);
298-
}
299-
300277
axiom fn axiom_pte_size_eq_size_of();
301278

302279
proof fn lemma_pte_walk_fills_page() {
303-
Self::lemma_nr_subpage_per_huge_eq_nr_entries();
280+
Self::lemma_page_table_config_constant_requirements();
304281
Self::axiom_pte_size_eq_size_of();
305282
}
306283

307-
proof fn lemma_top_level_index_range_within_nr_entries() {
308-
assert(Self::TOP_LEVEL_INDEX_RANGE_spec().end == 512usize);
309-
assert(crate::specs::arch::NR_ENTRIES == 512usize);
310-
}
311-
312284
axiom fn axiom_pte_align_divides_size();
313285

314286
axiom fn item_roundtrip(item: Self::Item, paddr: Paddr, level: PagingLevel, prop: PageProperty);

ostd/src/mm/page_table/mod.rs

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,10 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
183183
/// The paging constants.
184184
type C: PagingConstsTrait;
185185

186-
/// Bounds enforced by the upstream `vaddr_range` const assertions:
187-
/// the configured top-level range must fit inside the architecture's
188-
/// positional virtual-address width.
189-
proof fn lemma_top_level_index_range_bounds()
186+
/// Core constant properties that each config must prove.
187+
/// Combines bounds on the top-level index range, leading-bits
188+
/// constraints, and the NR_ENTRIES identity.
189+
proof fn lemma_page_table_config_constant_requirements()
190190
ensures
191191
(Self::TOP_LEVEL_INDEX_RANGE_spec().start as int) < (pow2(
192192
(Self::C::ADDRESS_WIDTH() as int - pte_index_bit_offset_spec::<Self::C>(
@@ -209,12 +209,6 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
209209
(Self::TOP_LEVEL_INDEX_RANGE_spec().end as int) * (pow2(
210210
pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
211211
) as int) <= usize::MAX as int,
212-
;
213-
214-
/// A non-zero high-bit prefix is only valid for configs whose managed
215-
/// range starts in the sign-extended high half.
216-
proof fn lemma_leading_bits_only_when_high_half()
217-
ensures
218212
Self::LEADING_BITS_spec() != 0usize ==> (Self::C::VA_SIGN_EXT() && (((
219213
Self::TOP_LEVEL_INDEX_RANGE_spec().start as int) * (pow2(
220214
pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
@@ -227,19 +221,23 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
227221
&&& Self::LEADING_BITS_spec() as int * 0x1_0000_0000_0000int
228222
== 0x1_0000_0000_0000_0000int - pow2(Self::C::ADDRESS_WIDTH() as nat) as int
229223
},
230-
;
231-
232-
/// The leading-bits field fits in 16 bits. Required for vaddr/Mapping
233-
/// arithmetic to stay within bounds.
234-
proof fn lemma_leading_bits_bounded()
235-
ensures
236224
Self::LEADING_BITS_spec() < 0x1_0000_usize,
225+
Self::C::BASE_PAGE_SIZE() / Self::C::PTE_SIZE() == NR_ENTRIES,
226+
pow2(
227+
(Self::C::ADDRESS_WIDTH() as int - pte_index_bit_offset_spec::<Self::C>(
228+
Self::C::NR_LEVELS(),
229+
)) as nat,
230+
) as int == NR_ENTRIES as int,
237231
;
238232

239-
proof fn lemma_nr_subpage_per_huge_eq_nr_entries()
233+
/// Properties derived from the constant requirements.
234+
/// Implementors get this for free.
235+
proof fn lemma_page_table_config_derived_properties()
240236
ensures
241-
Self::C::BASE_PAGE_SIZE() / Self::C::PTE_SIZE() == NR_ENTRIES,
242-
;
237+
Self::TOP_LEVEL_INDEX_RANGE_spec().end <= NR_ENTRIES,
238+
{
239+
Self::lemma_page_table_config_constant_requirements();
240+
}
243241

244242
/// Layout identity: the PTE type's Rust `size_of` matches the config's
245243
/// `PTE_SIZE_spec`. Concrete impls satisfy this via their `global
@@ -256,15 +254,6 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
256254
NR_ENTRIES * core::mem::size_of::<Self::E>() == crate::specs::arch::PAGE_SIZE,
257255
;
258256

259-
/// The top-level index range fits within a single PT-node. Concretely
260-
/// `0..256` (UserPtConfig) or `256..512` (KernelPtConfig); both have
261-
/// `end <= NR_ENTRIES`. Used by PT-node `on_drop` to bound
262-
/// `range.start * size_of::<C::E>() <= PAGE_SIZE`.
263-
proof fn lemma_top_level_index_range_within_nr_entries()
264-
ensures
265-
Self::TOP_LEVEL_INDEX_RANGE_spec().end <= NR_ENTRIES,
266-
;
267-
268257
// dubious: why is this an axiom
269258
/// `align_of::<E>()` divides `size_of::<E>()`. True for any sized Rust
270259
/// type (the alignment divides the size by the layout rules), but
@@ -820,7 +809,7 @@ fn top_level_index_width<C: PageTableConfig>() -> (ret: usize)
820809
{
821810
proof {
822811
C::lemma_paging_consts_properties();
823-
C::lemma_top_level_index_range_bounds();
812+
C::lemma_page_table_config_constant_requirements();
824813
}
825814

826815
C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
@@ -900,7 +889,7 @@ fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> (ret: bool)
900889
{
901890
let address_width = C::ADDRESS_WIDTH();
902891
proof {
903-
C::lemma_top_level_index_range_bounds();
892+
C::lemma_page_table_config_constant_requirements();
904893
assert(0 < address_width as int <= 64);
905894
}
906895

@@ -956,7 +945,7 @@ fn vaddr_range_bounds<C: PageTableConfig>() -> (ret: (Vaddr, Vaddr))
956945

957946
proof {
958947
lemma_vaddr_range_bounds_spec_unfold::<C>();
959-
C::lemma_top_level_index_range_bounds();
948+
C::lemma_page_table_config_constant_requirements();
960949
crate::specs::mm::page_table::vaddr_range_proofs::lemma_idx_times_pow2_bound::<C>(
961950
start,
962951
end,
@@ -967,7 +956,7 @@ fn vaddr_range_bounds<C: PageTableConfig>() -> (ret: (Vaddr, Vaddr))
967956
let sign_bit_set = sign_bit_of_va::<C>(pt_start);
968957
if va_sign_ext && sign_bit_set {
969958
proof {
970-
C::lemma_leading_bits_only_when_high_half();
959+
C::lemma_page_table_config_constant_requirements();
971960
assert(va_sign_ext == C::VA_SIGN_EXT());
972961
let off = pte_index_bit_offset_spec::<C::C>(C::NR_LEVELS()) as nat;
973962
let aw_m1 = (C::ADDRESS_WIDTH() - 1) as nat;
@@ -980,9 +969,9 @@ fn vaddr_range_bounds<C: PageTableConfig>() -> (ret: (Vaddr, Vaddr))
980969
} else {
981970
proof {
982971
// The if-condition was false, so either va_sign_ext is false
983-
// or sign_bit_set is false. The contrapositive of
984-
// `lemma_leading_bits_only_when_high_half` gives LEADING_BITS == 0.
985-
C::lemma_leading_bits_only_when_high_half();
972+
// or sign_bit_set is false. The contrapositive of the
973+
// leading-bits requirement gives LEADING_BITS == 0.
974+
C::lemma_page_table_config_constant_requirements();
986975
assert(!va_sign_ext || !sign_bit_set);
987976
// Bridge exec bool to spec form. `va_sign_ext == C::VA_SIGN_EXT()`
988977
// by `when_used_as_spec`; `sign_bit_set == ((pt_start as int /

ostd/src/mm/page_table/node/entry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> {
965965
new_owner.value.node().metaregion_sound_node(*regions),
966966
{
967967
proof {
968-
C::lemma_nr_subpage_per_huge_eq_nr_entries();
968+
C::lemma_page_table_config_constant_requirements();
969969
}
970970

971971
proof {

ostd/src/mm/page_table/node/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,8 @@ unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
163163

164164
proof {
165165
C::lemma_pte_walk_fills_page();
166-
C::lemma_top_level_index_range_within_nr_entries();
167-
C::lemma_nr_subpage_per_huge_eq_nr_entries();
168-
C::lemma_top_level_index_range_bounds();
166+
C::lemma_page_table_config_derived_properties();
167+
C::lemma_page_table_config_constant_requirements();
169168
vstd::arithmetic::mul::lemma_mul_inequality(
170169
range.start as int,
171170
NR_ENTRIES as int,
@@ -212,9 +211,8 @@ unsafe impl<C: PageTableConfig> AnyFrameMeta for PageTablePageMeta<C> {
212211

213212
proof {
214213
C::lemma_pte_walk_fills_page();
215-
C::lemma_top_level_index_range_within_nr_entries();
216-
C::lemma_nr_subpage_per_huge_eq_nr_entries();
217-
C::lemma_top_level_index_range_bounds();
214+
C::lemma_page_table_config_derived_properties();
215+
C::lemma_page_table_config_constant_requirements();
218216
vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way(
219217
size_of_e,
220218
NR_ENTRIES as int,

ostd/src/mm/vm_space.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ unsafe impl PageTableConfig for UserPtConfig {
16211621

16221622
type C = PagingConsts;
16231623

1624-
proof fn lemma_top_level_index_range_bounds() {
1624+
proof fn lemma_page_table_config_constant_requirements() {
16251625
use crate::mm::nr_subpage_per_huge;
16261626
use crate::mm::page_table::{nr_pte_index_bits, pte_index_bit_offset_spec};
16271627
use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds, pow2};
@@ -1634,20 +1634,7 @@ unsafe impl PageTableConfig for UserPtConfig {
16341634
lemma_usize_pow2_ilog2(12);
16351635
lemma_usize_pow2_ilog2(9);
16361636
lemma_pow2_adds(9, 39);
1637-
}
1638-
1639-
proof fn lemma_leading_bits_only_when_high_half() {
1640-
use crate::mm::page_table::pte_index_bit_offset_spec;
1641-
use vstd::arithmetic::power2::{lemma_pow2_pos, pow2};
1642-
1643-
Self::lemma_top_level_index_range_bounds();
16441637
assert(Self::LEADING_BITS_spec() == 0usize);
1645-
assert(Self::TOP_LEVEL_INDEX_RANGE_spec().start == 0_usize);
1646-
let numerator = (Self::TOP_LEVEL_INDEX_RANGE_spec().start as int) * (pow2(
1647-
pte_index_bit_offset_spec::<Self::C>(Self::C::NR_LEVELS()) as nat,
1648-
) as int);
1649-
let denominator = pow2((Self::C::ADDRESS_WIDTH() - 1) as nat) as int;
1650-
lemma_pow2_pos((Self::C::ADDRESS_WIDTH() - 1) as nat);
16511638
}
16521639

16531640
type Item = MappedItem;
@@ -1676,28 +1663,13 @@ unsafe impl PageTableConfig for UserPtConfig {
16761663
MappedItem { frame, prop }
16771664
}
16781665

1679-
proof fn lemma_nr_subpage_per_huge_eq_nr_entries() {
1680-
assert(Self::C::BASE_PAGE_SIZE() == 4096usize);
1681-
assert(Self::C::PTE_SIZE() == 8usize);
1682-
assert(NR_ENTRIES == 512usize);
1683-
}
1684-
1685-
proof fn lemma_leading_bits_bounded() {
1686-
assert(Self::LEADING_BITS_spec() == 0usize);
1687-
}
1688-
16891666
axiom fn axiom_pte_size_eq_size_of();
16901667

16911668
proof fn lemma_pte_walk_fills_page() {
1692-
Self::lemma_nr_subpage_per_huge_eq_nr_entries();
1669+
Self::lemma_page_table_config_constant_requirements();
16931670
Self::axiom_pte_size_eq_size_of();
16941671
}
16951672

1696-
proof fn lemma_top_level_index_range_within_nr_entries() {
1697-
assert(Self::TOP_LEVEL_INDEX_RANGE_spec().end == 256usize);
1698-
assert(NR_ENTRIES == 512usize);
1699-
}
1700-
17011673
axiom fn axiom_pte_align_divides_size();
17021674

17031675
axiom fn item_roundtrip(item: Self::Item, paddr: Paddr, level: PagingLevel, prop: PageProperty);

0 commit comments

Comments
 (0)