1use crate::specs::arch::*;
4use vstd::arithmetic::div_mod::group_div_basics;
5use vstd::arithmetic::power2::*;
6use vstd::prelude::*;
7
8pub type Vaddr = usize;
10
11pub type Paddr = usize;
13
14pub(crate) mod dma;
15pub mod frame;
16pub mod io;
18pub mod kspace;
19pub(crate) mod page_prop;
20pub mod page_table;
21pub mod tlb;
22pub mod vm_space;
23
24#[cfg(ktest)]
25mod test;
26
27use core::{fmt::Debug, ops::Range};
28
29pub use self::{
30 dma::{Daddr, DmaCoherent, HasDaddr},
31 frame::{
32 Frame,
33 allocator::FrameAllocOptions,
34 segment::{Segment, USegment},
35 unique::UniqueFrame,
36 untyped::{AnyUFrameMeta, UFrame, UntypedMem},
37 },
38 io::{
39 Fallible, FallibleVmRead, FallibleVmWrite, Infallible, PodOnce, VmIo, VmIoOnce, VmReader,
40 VmWriter,
41 },
42 page_prop::{CachePolicy, PageFlags, PageProperty},
43 vm_space::VmSpace,
44};
45pub(crate) use self::{
46 kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, page_table::PageTable,
47};
48pub(crate) use crate::arch::mm::PagingConsts;
49
50pub(crate) use page_table::largest_pages;
52
53pub type PagingLevel = u8;
55
56verus! {
57
58pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static {
61 spec fn BASE_PAGE_SIZE_spec() -> usize;
62
63 #[verifier::when_used_as_spec(BASE_PAGE_SIZE_spec)]
66 fn BASE_PAGE_SIZE() -> (res: usize)
67 returns
68 Self::BASE_PAGE_SIZE(),
69 ;
70
71 spec fn NR_LEVELS_spec() -> PagingLevel;
72
73 #[verifier::when_used_as_spec(NR_LEVELS_spec)]
79 fn NR_LEVELS() -> (res: PagingLevel)
80 returns
81 Self::NR_LEVELS(),
82 ;
83
84 spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel;
85
86 #[verifier::when_used_as_spec(HIGHEST_TRANSLATION_LEVEL_spec)]
89 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel
90 returns
91 Self::HIGHEST_TRANSLATION_LEVEL(),
92 ;
93
94 spec fn PTE_SIZE_spec() -> usize;
95
96 #[verifier::when_used_as_spec(PTE_SIZE_spec)]
98 fn PTE_SIZE() -> (res: usize)
99 returns
100 Self::PTE_SIZE(),
101 ;
102
103 spec fn ADDRESS_WIDTH_spec() -> usize;
104
105 #[verifier::when_used_as_spec(ADDRESS_WIDTH_spec)]
108 fn ADDRESS_WIDTH() -> (res: usize)
109 returns
110 Self::ADDRESS_WIDTH(),
111 ;
112
113 spec fn VA_SIGN_EXT_spec() -> bool;
114
115 #[verifier::when_used_as_spec(VA_SIGN_EXT_spec)]
127 fn VA_SIGN_EXT() -> bool
128 returns
129 Self::VA_SIGN_EXT(),
130 ;
131
132 proof fn lemma_paging_consts_requirements()
149 ensures
150 0 < Self::BASE_PAGE_SIZE(),
151 is_pow2(Self::BASE_PAGE_SIZE() as int),
152 Self::NR_LEVELS() > 0,
153 is_pow2(Self::PTE_SIZE() as int),
154 0 < Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
155 0 < Self::ADDRESS_WIDTH() < usize::BITS,
156 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2()
157 * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(),
158 Self::PTE_SIZE() == core::mem::size_of::<usize>(),
159 Self::BASE_PAGE_SIZE() == PAGE_SIZE,
163 Self::NR_LEVELS() == NR_LEVELS,
164 Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES,
165 ;
166
167 proof fn lemma_paging_consts_properties()
171 ensures
172 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() * (
175 Self::NR_LEVELS() - 1) <= Self::ADDRESS_WIDTH(),
176 0 < Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
177 NR_ENTRIES * Self::PTE_SIZE() == PAGE_SIZE,
178 0 < Self::BASE_PAGE_SIZE(),
181 is_pow2(Self::BASE_PAGE_SIZE() as int),
182 Self::NR_LEVELS() > 0,
183 is_pow2(Self::PTE_SIZE() as int),
184 0 < Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
185 0 < Self::ADDRESS_WIDTH() < usize::BITS,
186 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2()
187 * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(),
188 Self::PTE_SIZE() == core::mem::size_of::<usize>(),
189 Self::BASE_PAGE_SIZE() == PAGE_SIZE,
193 Self::NR_LEVELS() == NR_LEVELS,
194 Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES,
195 {
196 Self::lemma_paging_consts_requirements();
197 broadcast use group_div_basics;
198
199 }
200}
201
202pub open spec fn page_size_spec(level: PagingLevel) -> usize {
203 (PAGE_SIZE * pow2(
204 (nr_subpage_per_huge::<PagingConsts>().ilog2() * (level - 1)) as nat,
205 )) as usize
206}
207
208#[verifier::when_used_as_spec(page_size_spec)]
212pub fn page_size(level: PagingLevel) -> (ret: usize)
213 requires
214 1 <= level <= NR_LEVELS + 1,
215 ensures
216 ret == page_size_spec(level),
217 is_pow2(ret as int),
218 ret >= PAGE_SIZE,
219{
220 proof {
221 let index_bits: usize = nr_subpage_per_huge::<PagingConsts>().ilog2() as usize;
222 PagingConsts::lemma_paging_consts_properties();
223 crate::arch::mm::lemma_nr_subpage_per_huge_eq_nr_entries();
224 vstd::layout::unsigned_int_max_values();
225 vstd::arithmetic::power2::lemma2_to64();
226 vstd::arithmetic::power2::lemma2_to64_rest();
227 vstd_extra::external::ilog2::lemma_usize_pow2_ilog2(9);
228 let level_index: usize = (level - 1) as usize;
229 let shift: usize = (index_bits * level_index) as usize;
230 let ghost shift_nat = shift as nat;
231 let ghost page_shift = 12nat + shift_nat;
232
233 vstd::arithmetic::power2::lemma_pow2_adds(12, shift_nat);
234 if page_shift < 48nat {
235 vstd::arithmetic::power2::lemma_pow2_strictly_increases(page_shift, 48nat);
236 }
237 vstd::bits::lemma_usize_shl_is_mul(PAGE_SIZE, shift);
238 vstd_extra::external::ilog2::lemma_usize_pow2_shl_is_pow2(PAGE_SIZE, shift);
239 }
240 PAGE_SIZE << (nr_subpage_per_huge::<PagingConsts>().ilog2() as usize * (level as usize - 1))
241}
242
243#[verifier::inline]
244pub open spec fn nr_subpage_per_huge_spec<C: PagingConstsTrait>() -> usize {
245 C::BASE_PAGE_SIZE() / C::PTE_SIZE()
246}
247
248#[verifier::when_used_as_spec(nr_subpage_per_huge_spec)]
250pub fn nr_subpage_per_huge<C: PagingConstsTrait>() -> (res: usize)
251 ensures
252 res == nr_subpage_per_huge_spec::<C>(),
253{
254 proof {
255 C::lemma_paging_consts_properties();
256 }
257 C::BASE_PAGE_SIZE() / C::PTE_SIZE()
258}
259
260pub const MAX_USERSPACE_VADDR: Vaddr = 0x0000_8000_0000_0000_usize - PAGE_SIZE;
271
272pub const KERNEL_VADDR_RANGE: Range<Vaddr> =
277 0xffff_8000_0000_0000_usize..0xffff_ffff_ffff_0000_usize;
278
279pub trait HasPaddr {
281 fn paddr(&self) -> Paddr;
283}
284
285pub const fn is_page_aligned(p: usize) -> bool {
287 (p & (PAGE_SIZE - 1)) == 0
288}
289
290}