diff --git a/ostd/specs/arch/mod.rs b/ostd/specs/arch/mod.rs new file mode 100644 index 000000000..d9940a21d --- /dev/null +++ b/ostd/specs/arch/mod.rs @@ -0,0 +1,12 @@ +pub mod model; +pub use model::*; + +// Compatibility re-exports for proof modules that still use `specs::arch`. +// The authoritative values live in the executable memory/architecture modules. +pub use crate::{ + arch::mm::{NR_ENTRIES, NR_LEVELS}, + mm::{MAX_NR_PAGES, MAX_PADDR}, +}; + +mod x86; +pub use x86::*; diff --git a/ostd/specs/arch/model.rs b/ostd/specs/arch/model.rs new file mode 100644 index 000000000..bf312a4fa --- /dev/null +++ b/ostd/specs/arch/model.rs @@ -0,0 +1,63 @@ +use crate::mm::{Paddr, PagingConstsTrait, Vaddr}; +use vstd::prelude::*; + +verus! { + +/// The paging-related part of an architecture contract. +/// +/// The associated paging constants are still supplied by the existing +/// `PagingConstsTrait`; this trait only adds the architecture-wide physical +/// address bound and the proof that the two contracts are compatible. +pub trait ArchPagingModel { + type C: PagingConstsTrait; + + /// The exclusive upper bound for physical frame addresses. + spec fn max_paddr_spec() -> Paddr; + + proof fn lemma_paging_model_requirements() + ensures + 0 < Self::max_paddr_spec(), + Self::C::BASE_PAGE_SIZE() <= Self::max_paddr_spec(), + Self::max_paddr_spec() % Self::C::BASE_PAGE_SIZE() == 0, + ; +} + +/// A physical address that can identify a base-page frame for architecture `A`. +pub open spec fn valid_frame_paddr_for(pa: Paddr) -> bool { + pa % A::C::BASE_PAGE_SIZE() == 0 && pa < A::max_paddr_spec() +} + +/// The address-space part of an architecture contract. +pub trait ArchAddressSpaceModel: ArchPagingModel { + /// The base of the kernel's physical-to-virtual linear mapping. + spec fn linear_mapping_base_vaddr_spec() -> Vaddr; + + /// The first virtual address reserved for vmalloc mappings. + spec fn vmalloc_base_vaddr_spec() -> Vaddr; + + proof fn lemma_address_space_model_requirements() + ensures + Self::linear_mapping_base_vaddr_spec() % Self::C::BASE_PAGE_SIZE() == 0, + Self::linear_mapping_base_vaddr_spec() < Self::vmalloc_base_vaddr_spec(), + Self::max_paddr_spec() < Self::vmalloc_base_vaddr_spec() + - Self::linear_mapping_base_vaddr_spec(), + Self::max_paddr_spec() + Self::linear_mapping_base_vaddr_spec() < usize::MAX, + ; +} + +/// Convert a physical address through architecture `A`'s linear mapping. +pub open spec fn paddr_to_vaddr_for(pa: Paddr) -> Vaddr { + (pa + A::linear_mapping_base_vaddr_spec()) as usize +} + +/// Convert a linear-mapped virtual address back to a physical address. +pub open spec fn vaddr_to_paddr_for(va: Vaddr) -> Paddr { + (va - A::linear_mapping_base_vaddr_spec()) as usize +} + +/// The top-level contract used by architecture-independent specifications. +pub trait ArchTrait: ArchAddressSpaceModel { + +} + +} // verus! diff --git a/ostd/specs/arch/x86/mod.rs b/ostd/specs/arch/x86/mod.rs index af7bd7a88..f1d217c26 100644 --- a/ostd/specs/arch/x86/mod.rs +++ b/ostd/specs/arch/x86/mod.rs @@ -3,13 +3,17 @@ use vstd::prelude::*; use vstd::arithmetic::power2::{lemma_pow2_adds, lemma2_to64, lemma2_to64_rest, pow2}; use vstd_extra::prelude::*; +use super::model::{self, ArchAddressSpaceModel, ArchPagingModel, ArchTrait}; + +use crate::arch::mm::{NR_ENTRIES, NR_LEVELS}; use crate::specs::mm::{ frame::mapping::lemma_meta_to_frame_soundness, page_table::{nr_pte_index_bits_spec, pte_index_bit_offset_spec}, }; use crate::mm::{ - Paddr, PagingConstsTrait, Vaddr, + CurrentPagingConstsTrait, MAX_NR_PAGES, MAX_PADDR, Paddr, PagingConstsTrait, PagingLevel, + Vaddr, frame::meta::{META_SLOT_SIZE, mapping::meta_to_frame}, kspace::{FRAME_METADATA_RANGE, LINEAR_MAPPING_BASE_VADDR, VMALLOC_BASE_VADDR, paddr_to_vaddr}, page_size, @@ -22,37 +26,72 @@ global size_of usize == 8; global size_of isize == 8; -// The following constants are the same as those defined in `ostd::arch::mm::x86_64`, -// but we record their actual values for better proof automation. -/// Page size. -pub const PAGE_SIZE: usize = 4096; +/// Page size used by the current verification target. +pub const PAGE_SIZE: usize = crate::arch::mm::x86_base_page_size!(); -/// The maximum number of entries in a page table node -pub const NR_ENTRIES: usize = 512; +pub open spec fn valid_frame_paddr(paddr: Paddr) -> bool { + &&& paddr % PAGE_SIZE == 0 + &&& paddr < MAX_PADDR +} -/// The maximum level of a page table node. -pub const NR_LEVELS: usize = 4; +/// The x86 instance of the architecture-wide specification contract. +pub struct X86Arch; -/// Parameterized maximum physical address. -pub const MAX_PADDR: usize = 0x8000_0000; +impl ArchPagingModel for X86Arch { + type C = crate::arch::mm::PagingConsts; -pub const MAX_NR_PAGES: u64 = (MAX_PADDR / PAGE_SIZE) as u64; + open spec fn max_paddr_spec() -> Paddr { + MAX_PADDR + } -pub open spec fn valid_frame_paddr(paddr: Paddr) -> bool { - &&& paddr % PAGE_SIZE == 0 - &&& paddr < MAX_PADDR + proof fn lemma_paging_model_requirements() { + Self::C::lemma_paging_consts_requirements(); + + } } -} // verus! -verus! { +impl ArchAddressSpaceModel for X86Arch { + open spec fn linear_mapping_base_vaddr_spec() -> Vaddr { + LINEAR_MAPPING_BASE_VADDR + } + + open spec fn vmalloc_base_vaddr_spec() -> Vaddr { + VMALLOC_BASE_VADDR + } + + proof fn lemma_address_space_model_requirements() { + Self::C::lemma_paging_consts_requirements(); + Self::lemma_paging_model_requirements(); + assert(Self::linear_mapping_base_vaddr_spec() % Self::C::BASE_PAGE_SIZE() == 0) + by (compute_only); + + assert(Self::max_paddr_spec() < Self::vmalloc_base_vaddr_spec() + - Self::linear_mapping_base_vaddr_spec()) by (compute_only); + + } +} + +impl ArchTrait for X86Arch { + +} + +/// The architecture selected by the current verification target. +pub type CurrentArch = X86Arch; + +pub proof fn lemma_valid_frame_paddr_model_equivalent(paddr: Paddr) + ensures + valid_frame_paddr(paddr) == model::valid_frame_paddr_for::(paddr), +{ + CurrentArch::lemma_paging_model_requirements(); +} pub proof fn lemma_linear_mapping_base_vaddr_properties() ensures LINEAR_MAPPING_BASE_VADDR % PAGE_SIZE == 0, LINEAR_MAPPING_BASE_VADDR < VMALLOC_BASE_VADDR, { - assert(LINEAR_MAPPING_BASE_VADDR % PAGE_SIZE == 0) by (compute_only); - assert(LINEAR_MAPPING_BASE_VADDR < VMALLOC_BASE_VADDR) by (compute_only); + CurrentArch::lemma_address_space_model_requirements(); + } /// There is not an executable version in the source code. @@ -61,7 +100,7 @@ pub open spec fn vaddr_to_paddr(va: Vaddr) -> usize recommends LINEAR_MAPPING_BASE_VADDR <= va < VMALLOC_BASE_VADDR, { - (va - LINEAR_MAPPING_BASE_VADDR) as usize + model::vaddr_to_paddr_for::(va) } pub broadcast proof fn lemma_paddr_to_vaddr_properties(pa: Paddr) @@ -87,8 +126,8 @@ pub proof fn lemma_max_paddr_range() MAX_PADDR < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR, MAX_PADDR + LINEAR_MAPPING_BASE_VADDR < usize::MAX, { - assert(MAX_PADDR < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR) by (compute_only); - assert(MAX_PADDR + LINEAR_MAPPING_BASE_VADDR < usize::MAX) by (compute_only); + CurrentArch::lemma_address_space_model_requirements(); + } pub broadcast proof fn lemma_meta_frame_vaddr_properties(meta: Vaddr) @@ -113,7 +152,7 @@ pub broadcast proof fn lemma_meta_frame_vaddr_properties(meta: Vaddr) // Here are some architecture-specific const value properties. // Any use of this lemma in architecture-independent code should be removed. -pub(crate) proof fn lemma_arch_specific_consts_properties() +pub(crate) proof fn lemma_arch_specific_consts_properties() ensures C::BASE_PAGE_SIZE().ilog2() == 12u32, nr_pte_index_bits_spec::() == 9usize, @@ -127,6 +166,7 @@ pub(crate) proof fn lemma_arch_specific_consts_properties( 0xffff_int * 0x1_0000_0000_0000int + pow2(48) - 1 == 0xffff_ffff_ffff_ffffint, { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); lemma2_to64(); lemma2_to64_rest(); lemma_usize_pow2_ilog2(12); diff --git a/ostd/specs/mm/page_table/cursor/owners.rs b/ostd/specs/mm/page_table/cursor/owners.rs index 487043fe6..4c2b3cd68 100644 --- a/ostd/specs/mm/page_table/cursor/owners.rs +++ b/ostd/specs/mm/page_table/cursor/owners.rs @@ -34,7 +34,7 @@ use crate::specs::{ use crate::arch::mm::PagingConsts; use crate::mm::{ - MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr, + CurrentPagingConstsTrait, MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr, frame::meta::{REF_COUNT_MAX, REF_COUNT_UNIQUE, REF_COUNT_UNUSED}, kspace::KernelPtConfig, nr_subpage_per_huge, @@ -2369,6 +2369,7 @@ pub proof fn lemma_view_in_vaddr_range<'rcu, C: PageTableConfig>(owner: &CursorO }, { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); C::lemma_page_table_config_constant_properties(); lemma_arch_specific_consts_properties::(); diff --git a/ostd/specs/mod.rs b/ostd/specs/mod.rs index bc8234611..f316bf901 100644 --- a/ostd/specs/mod.rs +++ b/ostd/specs/mod.rs @@ -3,7 +3,6 @@ #[allow(unused_braces)] #[allow(rustdoc::invalid_rust_codeblocks)] #[allow(rustdoc::invalid_html_tags)] -#[path = "arch/x86/mod.rs"] pub mod arch; #[allow(unused_parens)] #[allow(unused_braces)] diff --git a/ostd/src/arch/x86/mm/mod.rs b/ostd/src/arch/x86/mm/mod.rs index 4a2bc573d..27eb55123 100644 --- a/ostd/src/arch/x86/mm/mod.rs +++ b/ostd/src/arch/x86/mm/mod.rs @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 #![expect(dead_code)] -use crate::specs::arch::{MAX_PADDR, NR_ENTRIES, NR_LEVELS}; use vstd::arithmetic::power2::*; use vstd::prelude::*; use vstd_extra::panic::may_panic; @@ -15,12 +14,18 @@ use core::ops::Range; pub(crate) use util::{__memcpy_fallible, __memset_fallible}; //use x86_64::{instructions::tlb, structures::paging::PhysFrame, VirtAddr}; -use crate::specs::arch::PAGE_SIZE; +macro_rules! x86_base_page_size { + () => { + 4096usize + }; +} +pub(crate) use x86_base_page_size; + use crate::{ mm::{ page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags as PrivFlags}, page_table::{PageTableEntryTrait, PageTableFrag}, - Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr, + CurrentPagingConstsTrait, Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr, MAX_PADDR, }, Pod, }; @@ -28,6 +33,28 @@ use crate::{ mod util; verus! { + +/// Size of a base page on x86-64. +pub const PAGE_SIZE: usize = x86_base_page_size!(); + +/// Size of an x86-64 page-table entry. +pub const PTE_SIZE: usize = 8; + +/// Number of entries in an x86-64 page-table node. +pub const NR_ENTRIES: usize = 512; + +/// Number of translation levels used by the current x86-64 configuration. +pub const NR_LEVELS: usize = 4; + +/// Width of canonical virtual addresses used by the current configuration. +pub const ADDRESS_WIDTH: usize = 48; + +/// Highest level at which a PTE may directly map a page. +pub const HIGHEST_TRANSLATION_LEVEL: PagingLevel = 2; + +/// Whether virtual addresses use sign extension. +pub const VA_SIGN_EXT: bool = true; + #[verifier::allow(autoderive_clone_without_spec)] #[derive(Clone, Debug, Default)] pub struct PagingConsts {} @@ -36,71 +63,71 @@ impl PagingConstsTrait for PagingConsts { // Expansion for BASE_PAGE_SIZE #[verifier::inline] open spec fn BASE_PAGE_SIZE_spec() -> usize { - 4096 + PAGE_SIZE } #[inline(always)] fn BASE_PAGE_SIZE() -> usize { - 4096 + PAGE_SIZE } // Expansion for NR_LEVELS #[verifier::inline] open spec fn NR_LEVELS_spec() -> PagingLevel { - 4 + NR_LEVELS as PagingLevel } #[inline(always)] fn NR_LEVELS() -> PagingLevel { - 4 + NR_LEVELS as PagingLevel } // Expansion for ADDRESS_WIDTH #[verifier::inline] open spec fn ADDRESS_WIDTH_spec() -> usize { - 48 + ADDRESS_WIDTH } #[inline(always)] fn ADDRESS_WIDTH() -> usize { - 48 + ADDRESS_WIDTH } // Expansion for HIGHEST_TRANSLATION_LEVEL #[verifier::inline] open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel { - 2 + HIGHEST_TRANSLATION_LEVEL } #[inline(always)] fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel { - 2 + HIGHEST_TRANSLATION_LEVEL } #[verifier::inline] open spec fn VA_SIGN_EXT_spec() -> bool { - true + VA_SIGN_EXT } #[inline(always)] fn VA_SIGN_EXT() -> bool { - true + VA_SIGN_EXT } // Expansion for PTE_SIZE #[verifier::inline] open spec fn PTE_SIZE_spec() -> usize { - 8 + PTE_SIZE } #[inline(always)] fn PTE_SIZE() -> (res: usize) { - 8 + PTE_SIZE } proof fn lemma_paging_consts_requirements() @@ -116,6 +143,15 @@ impl PagingConstsTrait for PagingConsts { } } +impl CurrentPagingConstsTrait for PagingConsts { + proof fn lemma_current_paging_consts_requirements() { + Self::lemma_paging_consts_requirements(); + assert(Self::BASE_PAGE_SIZE() == PAGE_SIZE) by (compute_only); + assert(Self::NR_LEVELS() == NR_LEVELS as PagingLevel) by (compute_only); + assert(Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES) by (compute_only); + } +} + pub proof fn lemma_nr_subpage_per_huge_eq_nr_entries() ensures crate::mm::nr_subpage_per_huge::() == NR_ENTRIES, @@ -392,7 +428,6 @@ impl PageTableEntryTrait for PageTableEntry { fn paddr(&self) -> Paddr { proof { self.lemma_paddr_is_page_aligned(); - assume(self.0 & Self::PHYS_ADDR_MASK < MAX_PADDR); } self.0 & Self::PHYS_ADDR_MASK } diff --git a/ostd/src/mm/kspace/mod.rs b/ostd/src/mm/kspace/mod.rs index 4ecb4cfd4..bb4413f05 100644 --- a/ostd/src/mm/kspace/mod.rs +++ b/ostd/src/mm/kspace/mod.rs @@ -44,7 +44,7 @@ pub(crate) mod kvirt_area; mod test; use super::{ - Paddr, PagingConstsTrait, Vaddr, + CurrentPagingConstsTrait, Paddr, PagingConstsTrait, Vaddr, frame::{ Frame, Segment, meta::{AnyFrameMeta, MetaPageMeta, MetaSlot, mapping}, @@ -177,6 +177,7 @@ unsafe impl PageTableConfig for KernelPtConfig { use crate::mm::nr_subpage_per_huge; use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds, pow2}; Self::C::lemma_paging_consts_properties(); + Self::C::lemma_current_paging_consts_requirements(); PageTableEntry::lemma_layout(); lemma2_to64(); lemma2_to64_rest(); diff --git a/ostd/src/mm/mod.rs b/ostd/src/mm/mod.rs index d60bf1a5b..c1721d070 100644 --- a/ostd/src/mm/mod.rs +++ b/ostd/src/mm/mod.rs @@ -1,6 +1,5 @@ // SPDX-License-Identifier: MPL-2.0 //! Virtual memory (VM). -use crate::specs::arch::*; use vstd::arithmetic::div_mod::group_div_basics; use vstd::arithmetic::power2::*; use vstd::prelude::*; @@ -46,6 +45,7 @@ pub(crate) use self::{ kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, page_table::PageTable, }; pub(crate) use crate::arch::mm::PagingConsts; +pub use crate::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE}; // Re-export largest_pages from page_table pub(crate) use page_table::largest_pages; @@ -55,6 +55,14 @@ pub type PagingLevel = u8; verus! { +/// Current verification upper bound for tracked physical addresses. +/// +/// This is a memory-model bound, not the architectural physical-address width. +pub const MAX_PADDR: Paddr = 0x8000_0000; + +/// Maximum number of base-page frames represented by the current memory model. +pub const MAX_NR_PAGES: u64 = (MAX_PADDR / PAGE_SIZE) as u64; + /// A minimal set of constants that determines the paging system. /// This provides an abstraction over most paging modes in common architectures. pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static { @@ -134,17 +142,6 @@ pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static { /// NOTE: The postcondition is designed to be minimal, to actually be used in proofs, call `lemma_paging_consts_properties` /// instead to get all the properties that are derived from the requirements. /// - /// FIXME: General architecture support. - /// All configs in vostd use the same value for the per-config - /// `NR_LEVELS()` as the architecture-level constant `NR_LEVELS` - /// (= 4 for x86_64). This is *implicit* in the cursor framework: - /// `CursorOwner::inv()` hardcodes `self.level <= NR_LEVELS` (const) - /// for cursors over any `C: PagingConstsTrait`, so a config whose - /// `NR_LEVELS_spec()` exceeded `NR_LEVELS` would be unusable. This - /// lemma exposes that equality as a usable fact so generic proofs - /// can chain `level != C::NR_LEVELS_spec()` to `level < NR_LEVELS` - /// (e.g. `Cursor::find_next_impl`'s PageTable-branch gate ⟹ - /// `CursorMut::take_next`'s `replace_cur_entry` discharge). proof fn lemma_paging_consts_requirements() ensures 0 < Self::BASE_PAGE_SIZE(), @@ -156,12 +153,6 @@ pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static { Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(), Self::PTE_SIZE() == core::mem::size_of::(), - // The following statement holds for all architectures, - // but the actual value of the constants may vary. - // Maybe we can remove this requirement. - Self::BASE_PAGE_SIZE() == PAGE_SIZE, - Self::NR_LEVELS() == NR_LEVELS, - Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES, ; /// The derived properties of the paging constants. @@ -174,7 +165,6 @@ pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static { Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() * ( Self::NR_LEVELS() - 1) <= Self::ADDRESS_WIDTH(), 0 < Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(), - NR_ENTRIES * Self::PTE_SIZE() == PAGE_SIZE, // Copied from the postcondition of `lemma_paging_consts_requirements` // so that we only need to call this lemma in proofs. 0 < Self::BASE_PAGE_SIZE(), @@ -186,25 +176,56 @@ pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static { Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(), Self::PTE_SIZE() == core::mem::size_of::(), - // The following statement holds for all architectures, - // but the actual value of the constants may vary. - // Maybe we can remove this requirement. - Self::BASE_PAGE_SIZE() == PAGE_SIZE, - Self::NR_LEVELS() == NR_LEVELS, - Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES, { Self::lemma_paging_consts_requirements(); broadcast use group_div_basics; + let base = Self::BASE_PAGE_SIZE() as int; + let pte = Self::PTE_SIZE() as int; + let levels = Self::NR_LEVELS() as int; + let base_bits = Self::BASE_PAGE_SIZE().ilog2() as int; + let index_bits = (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() as int; + assert(0 < base / pte) by { + vstd::arithmetic::div_mod::lemma_div_non_zero(base, pte); + }; + assert(base / pte <= base) by { + vstd::arithmetic::div_mod::lemma_div_is_ordered(0, base, pte); + }; + assert(base_bits + index_bits * (levels - 1) <= base_bits + index_bits * levels) + by (nonlinear_arith) + requires + 0 <= index_bits, + 1 <= levels, + ; } } -pub open spec fn page_size_spec(level: PagingLevel) -> usize { - (PAGE_SIZE * pow2( - (nr_subpage_per_huge::().ilog2() * (level - 1)) as nat, +/// Bridge between a paging configuration and the build-selected architecture. +/// +/// This is intentionally separate from [`PagingConstsTrait`]. Public paging +/// types still use build-selected constants in const-generic positions, while +/// generic paging specifications can range over any [`PagingConstsTrait`]. +pub trait CurrentPagingConstsTrait: PagingConstsTrait { + proof fn lemma_current_paging_consts_requirements() + ensures + Self::BASE_PAGE_SIZE() == PAGE_SIZE, + Self::NR_LEVELS() == NR_LEVELS as PagingLevel, + Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES, + ; +} + +/// The page-size formula for an explicit paging configuration. +pub open spec fn page_size_for_spec(level: PagingLevel) -> usize { + (C::BASE_PAGE_SIZE_spec() * pow2( + (nr_subpage_per_huge::().ilog2() * (level - 1)) as nat, )) as usize } +/// The page-size formula for the architecture selected by this build. +pub open spec fn page_size_spec(level: PagingLevel) -> usize { + page_size_for_spec::(level) +} + // /// The page size // pub const PAGE_SIZE: usize = page_size::(1); /// The page size at a given level. @@ -242,7 +263,7 @@ pub fn page_size(level: PagingLevel) -> (ret: usize) #[verifier::inline] pub open spec fn nr_subpage_per_huge_spec() -> usize { - C::BASE_PAGE_SIZE() / C::PTE_SIZE() + C::BASE_PAGE_SIZE_spec() / C::PTE_SIZE_spec() } /// The number of sub pages in a huge page. diff --git a/ostd/src/mm/page_table/cursor/mod.rs b/ostd/src/mm/page_table/cursor/mod.rs index c90411d33..fc156de2a 100644 --- a/ostd/src/mm/page_table/cursor/mod.rs +++ b/ostd/src/mm/page_table/cursor/mod.rs @@ -63,8 +63,9 @@ use crate::{ }; use super::{ - Child, ChildRef, Entry, EntryOwner, FrameView, PageTable, PageTableConfig, PageTableError, - PageTableGuard, PageTablePageMeta, PagingConstsTrait, PagingLevel, pte_index, + Child, ChildRef, CurrentPagingConstsTrait, Entry, EntryOwner, FrameView, PageTable, + PageTableConfig, PageTableError, PageTableGuard, PageTablePageMeta, PagingConstsTrait, + PagingLevel, pte_index, }; verus! { @@ -1085,6 +1086,7 @@ impl<'rcu, C: PageTableConfig, A: InAtomicMode> Cursor<'rcu, C, A> { } if !C::TOP_LEVEL_CAN_UNMAP_spec() { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); assert(self.level < NR_LEVELS); } } diff --git a/ostd/src/mm/page_table/mod.rs b/ostd/src/mm/page_table/mod.rs index bbb11f2ca..f4fae92ae 100644 --- a/ostd/src/mm/page_table/mod.rs +++ b/ostd/src/mm/page_table/mod.rs @@ -29,7 +29,7 @@ use core::{ }; use super::{ - Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr, + CurrentPagingConstsTrait, Paddr, PagingConstsTrait, PagingLevel, PodOnce, Vaddr, kspace::KernelPtConfig, nr_subpage_per_huge, page_prop::{CachePolicy, PageProperty}, @@ -181,7 +181,7 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static { type E: PageTableEntryTrait; /// The paging constants. - type C: PagingConstsTrait; + type C: CurrentPagingConstsTrait; /// The item that can be mapped into the virtual memory space using the /// page table. @@ -499,6 +499,7 @@ pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static { ) == NR_ENTRIES, { Self::C::lemma_paging_consts_properties(); + Self::C::lemma_current_paging_consts_requirements(); Self::lemma_page_table_config_constant_requirements(); } } @@ -562,6 +563,12 @@ impl PagingConstsTrait for C { } } +impl CurrentPagingConstsTrait for C { + proof fn lemma_current_paging_consts_requirements() { + C::C::lemma_current_paging_consts_requirements(); + } +} + /// Splits the address range into largest page table items. /// /// Each of the returned items is a tuple of the physical address and the @@ -626,6 +633,7 @@ fn top_level_index_width() -> (ret: usize) { proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); C::lemma_page_table_config_constant_properties(); } @@ -640,6 +648,7 @@ fn pt_va_range_start() -> (ret: Vaddr) { proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); let ghost idx_start = C::TOP_LEVEL_INDEX_RANGE().start; let ghost offset = pte_index_bit_offset_spec::(C::NR_LEVELS()); crate::specs::mm::page_table::vaddr_range_proofs::lemma_pt_va_range_start_shift_facts::( @@ -666,6 +675,7 @@ fn pt_va_range_end() -> (ret: Vaddr) let idx_end = C::TOP_LEVEL_INDEX_RANGE().end; proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); } let offset = pte_index_bit_offset::(C::NR_LEVELS()); @@ -818,7 +828,7 @@ fn nr_pte_index_bits() -> usize } /// The index of a VA's PTE in a page table node at the given level. -fn pte_index(va: Vaddr, level: PagingLevel) -> (res: usize) +fn pte_index(va: Vaddr, level: PagingLevel) -> (res: usize) requires 1 <= level <= NR_LEVELS, ensures @@ -827,6 +837,7 @@ fn pte_index(va: Vaddr, level: PagingLevel) -> (res: usize proof { let offset = pte_index_bit_offset_spec::(level); C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); lemma_arch_specific_consts_properties::(); assert(0 <= offset < usize::BITS) by (nonlinear_arith) requires @@ -850,7 +861,7 @@ fn pte_index(va: Vaddr, level: PagingLevel) -> (res: usize /// This function returns the bit offset of the least significant bit. Take /// x86-64 as an example, the `pte_index_bit_offset(2)` should return 21, which /// is 12 (the 4KiB in-page offset) plus 9 (index width in the level-1 table). -fn pte_index_bit_offset(level: PagingLevel) -> usize +fn pte_index_bit_offset(level: PagingLevel) -> usize requires 1 <= level <= NR_LEVELS, returns @@ -858,6 +869,7 @@ fn pte_index_bit_offset(level: PagingLevel) -> usize { proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); lemma_arch_specific_consts_properties::(); assert(12 + 9 * (level - 1) <= 39) by (nonlinear_arith) requires @@ -1673,12 +1685,16 @@ pub trait PageTableEntryTrait: /// The physical address recorded in the PTE is either: /// - the physical address of the next-level page table, or /// - the physical address of the page that the PTE maps to. + /// + /// This getter only guarantees page alignment. `paddr < MAX_PADDR` is an + /// obligation of well-formed owned PTEs, not of an arbitrary encoded PTE + /// word. spec fn paddr_spec(&self) -> Paddr; #[verifier::when_used_as_spec(paddr_spec)] fn paddr(&self) -> (res: Paddr) ensures - valid_frame_paddr(res), + res % PAGE_SIZE == 0, returns self.paddr(), ; diff --git a/ostd/src/mm/page_table/node/entry.rs b/ostd/src/mm/page_table/node/entry.rs index f8077839d..61180831f 100644 --- a/ostd/src/mm/page_table/node/entry.rs +++ b/ostd/src/mm/page_table/node/entry.rs @@ -12,7 +12,7 @@ use crate::mm::frame::{ meta::{REF_COUNT_MAX, REF_COUNT_UNUSED}, }; use crate::mm::page_table::*; -use crate::mm::{Paddr, PagingConstsTrait, PagingLevel, Vaddr}; +use crate::mm::{CurrentPagingConstsTrait, Paddr, PagingConstsTrait, PagingLevel, Vaddr}; use crate::specs::arch::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE}; use crate::specs::mm::frame::{ mapping::{frame_to_index, group_page_meta, meta_to_index}, @@ -991,6 +991,7 @@ impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> { proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); assert(nr_subpage_per_huge_spec::() == NR_ENTRIES); } @@ -1087,6 +1088,7 @@ impl<'a, 'rcu, C: PageTableConfig> Entry<'a, 'rcu, C> { proof { C::lemma_page_table_config_constant_properties(); C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); // Prove required facts while we still have new_owner.value.node available. let ghost the_node = new_owner.value().node(); diff --git a/ostd/src/mm/page_table/node/mod.rs b/ostd/src/mm/page_table/node/mod.rs index e1a0591a9..b265db1dd 100644 --- a/ostd/src/mm/page_table/node/mod.rs +++ b/ostd/src/mm/page_table/node/mod.rs @@ -72,6 +72,7 @@ use super::{PageTableConfig, PageTableEntryTrait, nr_subpage_per_huge}; use crate::{ mm::{ + CurrentPagingConstsTrait, PagingConstsTrait, PagingLevel, // FrameAllocOptions, Infallible, @@ -174,6 +175,7 @@ unsafe impl AnyFrameMeta for PageTablePageMeta { proof { C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); C::lemma_page_table_config_constant_properties(); vstd::arithmetic::mul::lemma_mul_inequality( range.start as int, @@ -217,6 +219,7 @@ unsafe impl AnyFrameMeta for PageTablePageMeta { proof { C::lemma_page_table_config_constant_properties(); C::lemma_paging_consts_properties(); + C::lemma_current_paging_consts_requirements(); vstd::arithmetic::mul::lemma_mul_is_distributive_sub_other_way( size_of_e, NR_ENTRIES as int, @@ -999,11 +1002,10 @@ impl PageTablePageMeta { ensures ({ let pte = Self::walk_pte_at_view(view, c); - pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed( - pte.paddr(), - self.level, - pte.prop(), - ) + pte.is_present() && pte.is_last(self.level) ==> { + &&& valid_frame_paddr(pte.paddr()) + &&& C::raw_item_well_formed(pte.paddr(), self.level, pte.prop()) + } }), { } @@ -1058,8 +1060,8 @@ impl PageTablePageMeta { } } - /// Every present leaf PTE encountered by the drop walk contains a canonical - /// raw item for the node's paging level. + /// Every present leaf PTE encountered by the drop walk contains a valid + /// frame address and a canonical raw item for the node's paging level. pub open spec fn walk_items_well_formed_from_view( self, reader: crate::mm::VmReader<'_, crate::mm::Infallible>, @@ -1072,11 +1074,10 @@ impl PageTablePageMeta { C::E, >() as int == 0 ==> { let pte = Self::walk_pte_at_view(view, c); - pte.is_present() && pte.is_last(self.level) ==> C::raw_item_well_formed( - pte.paddr(), - self.level, - pte.prop(), - ) + pte.is_present() && pte.is_last(self.level) ==> { + &&& valid_frame_paddr(pte.paddr()) + &&& C::raw_item_well_formed(pte.paddr(), self.level, pte.prop()) + } } } diff --git a/ostd/src/mm/vm_space.rs b/ostd/src/mm/vm_space.rs index c4abdfe24..d1bcb6e9a 100644 --- a/ostd/src/mm/vm_space.rs +++ b/ostd/src/mm/vm_space.rs @@ -45,7 +45,7 @@ use crate::mm::tlb::*; use crate::specs::mm::cpu::{AtomicCpuSet, CpuSet}; use crate::mm::{ - MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr, + CurrentPagingConstsTrait, MAX_USERSPACE_VADDR, Paddr, PagingConstsTrait, PagingLevel, Vaddr, io::{Fallible, VmReader, VmWriter}, page_prop::PageProperty, }; @@ -1764,6 +1764,7 @@ unsafe impl PageTableConfig for UserPtConfig { lemma_pow2_adds(9, 39); PageTableEntry::lemma_layout(); Self::C::lemma_paging_consts_properties(); + Self::C::lemma_current_paging_consts_requirements(); assert(Self::LEADING_BITS_spec() == 0usize); } }