1use vstd::{
4 arithmetic::{div_mod::group_div_basics, mul::lemma_mul_left_inequality, power2::*},
5 bits::lemma_usize_shl_is_mul,
6 prelude::*,
7};
8use vstd_extra::external::ilog2::{
9 lemma_pow2_is_pow2, lemma_usize_ilog2_ordered, lemma_usize_is_pow2_is_ilog2_pow2,
10 lemma_usize_pow2_shl_is_pow2,
11};
12
13use crate::specs::mm::page_table::{
14 lemma_page_size_is_pow2_pte_index_bit_offset, nr_pte_index_bits_spec,
15};
16
17pub type Vaddr = usize;
19
20pub type Paddr = usize;
22
23pub(crate) mod dma;
24pub mod frame;
25pub mod io;
27pub mod kspace;
28pub(crate) mod page_prop;
29pub mod page_table;
30pub mod tlb;
31pub mod vm_space;
32
33#[cfg(ktest)]
34mod test;
35
36use core::{fmt::Debug, ops::Range};
37
38pub use self::{
39 dma::{Daddr, DmaCoherent, HasDaddr},
40 frame::{
41 Frame,
42 allocator::FrameAllocOptions,
43 segment::{Segment, USegment},
44 unique::UniqueFrame,
45 untyped::{AnyUFrameMeta, UFrame, UntypedMem},
46 },
47 io::{
48 Fallible, FallibleVmRead, FallibleVmWrite, Infallible, PodOnce, VmIo, VmIoOnce, VmReader,
49 VmWriter,
50 },
51 page_prop::{CachePolicy, PageFlags, PageProperty},
52 vm_space::VmSpace,
53};
54pub(crate) use self::{
55 kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, page_table::PageTable,
56};
57pub(crate) use crate::arch::mm::PagingConsts;
58pub use crate::arch::mm::{NR_ENTRIES, NR_LEVELS, PAGE_SIZE};
59
60pub(crate) use page_table::largest_pages;
62
63pub type PagingLevel = u8;
65
66verus! {
67
68pub const MAX_PADDR: Paddr = 0x8000_0000;
78
79pub const MAX_NR_PAGES: u64 = (MAX_PADDR / PAGE_SIZE) as u64;
81
82pub trait PagingConstsTrait: Clone + Debug + Send + Sync + 'static {
85 spec fn BASE_PAGE_SIZE_spec() -> usize;
86
87 #[verifier::when_used_as_spec(BASE_PAGE_SIZE_spec)]
90 fn BASE_PAGE_SIZE() -> (res: usize)
91 returns
92 Self::BASE_PAGE_SIZE(),
93 ;
94
95 spec fn NR_LEVELS_spec() -> PagingLevel;
96
97 #[verifier::when_used_as_spec(NR_LEVELS_spec)]
103 fn NR_LEVELS() -> (res: PagingLevel)
104 returns
105 Self::NR_LEVELS(),
106 ;
107
108 spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel;
109
110 #[verifier::when_used_as_spec(HIGHEST_TRANSLATION_LEVEL_spec)]
113 fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel
114 returns
115 Self::HIGHEST_TRANSLATION_LEVEL(),
116 ;
117
118 spec fn PTE_SIZE_spec() -> usize;
119
120 #[verifier::when_used_as_spec(PTE_SIZE_spec)]
122 fn PTE_SIZE() -> (res: usize)
123 returns
124 Self::PTE_SIZE(),
125 ;
126
127 spec fn ADDRESS_WIDTH_spec() -> usize;
128
129 #[verifier::when_used_as_spec(ADDRESS_WIDTH_spec)]
132 fn ADDRESS_WIDTH() -> (res: usize)
133 returns
134 Self::ADDRESS_WIDTH(),
135 ;
136
137 spec fn VA_SIGN_EXT_spec() -> bool;
138
139 #[verifier::when_used_as_spec(VA_SIGN_EXT_spec)]
151 fn VA_SIGN_EXT() -> bool
152 returns
153 Self::VA_SIGN_EXT(),
154 ;
155
156 proof fn lemma_paging_consts_requirements()
162 ensures
163 0 < Self::BASE_PAGE_SIZE(),
164 is_pow2(Self::BASE_PAGE_SIZE() as int),
165 0 < Self::HIGHEST_TRANSLATION_LEVEL() <= Self::NR_LEVELS() < PagingLevel::MAX,
166 is_pow2(Self::PTE_SIZE() as int),
167 0 < Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
168 0 < Self::ADDRESS_WIDTH() < usize::BITS,
169 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2()
170 * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(),
171 Self::PTE_SIZE() == core::mem::size_of::<usize>(),
172 ;
173
174 proof fn lemma_paging_consts_properties()
178 ensures
179 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() * (
182 Self::NR_LEVELS() - 1) <= Self::ADDRESS_WIDTH(),
183 0 < Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
184 is_pow2((Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()) as int),
185 0 < Self::BASE_PAGE_SIZE(),
188 is_pow2(Self::BASE_PAGE_SIZE() as int),
189 0 < Self::HIGHEST_TRANSLATION_LEVEL() <= Self::NR_LEVELS() < PagingLevel::MAX,
190 is_pow2(Self::PTE_SIZE() as int),
191 0 < Self::PTE_SIZE() <= Self::BASE_PAGE_SIZE(),
192 0 < Self::ADDRESS_WIDTH() < usize::BITS,
193 Self::BASE_PAGE_SIZE().ilog2() + (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2()
194 * Self::NR_LEVELS() <= Self::ADDRESS_WIDTH(),
195 Self::PTE_SIZE() == core::mem::size_of::<usize>(),
196 {
197 Self::lemma_paging_consts_requirements();
198 broadcast use group_div_basics;
199
200 let base = Self::BASE_PAGE_SIZE() as int;
201 let pte = Self::PTE_SIZE() as int;
202 let levels = Self::NR_LEVELS() as int;
203 let base_bits = Self::BASE_PAGE_SIZE().ilog2() as int;
204 let index_bits = (Self::BASE_PAGE_SIZE() / Self::PTE_SIZE()).ilog2() as int;
205 assert(0 < base / pte) by {
206 vstd::arithmetic::div_mod::lemma_div_non_zero(base, pte);
207 };
208 assert(base / pte <= base) by {
209 vstd::arithmetic::div_mod::lemma_div_is_ordered(0, base, pte);
210 };
211 assert(base_bits + index_bits * (levels - 1) <= base_bits + index_bits * levels)
212 by (nonlinear_arith)
213 requires
214 0 <= index_bits,
215 1 <= levels,
216 ;
217 let page = Self::BASE_PAGE_SIZE();
218 let pte = Self::PTE_SIZE();
219 lemma_usize_is_pow2_is_ilog2_pow2(page);
220 lemma_usize_is_pow2_is_ilog2_pow2(pte);
221 lemma_usize_ilog2_ordered(pte, page);
222 lemma_pow2_subtracts(pte.ilog2() as nat, page.ilog2() as nat);
223 lemma_pow2_is_pow2((page.ilog2() - pte.ilog2()) as nat);
224 }
225
226 #[verifier::external_body]
234 proof fn axiom_current_paging_consts_hardcoded()
235 ensures
236 Self::BASE_PAGE_SIZE() == PAGE_SIZE,
237 Self::NR_LEVELS() == NR_LEVELS as PagingLevel,
238 Self::BASE_PAGE_SIZE() / Self::PTE_SIZE() == NR_ENTRIES,
239 {
240 }
241}
242
243pub open spec fn page_size_spec<C: PagingConstsTrait>(level: PagingLevel) -> usize {
244 (C::BASE_PAGE_SIZE() * pow2((nr_subpage_per_huge::<C>().ilog2() * (level - 1)) as nat)) as usize
245}
246
247#[verifier::when_used_as_spec(page_size_spec)]
251pub fn page_size<C: PagingConstsTrait>(level: PagingLevel) -> (ret: usize)
252 requires
253 1 <= level <= C::NR_LEVELS() + 1,
254 ensures
255 is_pow2(ret as int),
256 ret >= C::BASE_PAGE_SIZE(),
257 returns
258 page_size_spec::<C>(level),
259{
260 proof {
261 C::lemma_paging_consts_properties();
262 lemma_page_size_is_pow2_pte_index_bit_offset::<C>(level);
263 let shift = (nr_pte_index_bits_spec::<C>() * (level - 1)) as usize;
264 lemma_usize_is_pow2_is_ilog2_pow2(C::BASE_PAGE_SIZE());
265 lemma_pow2_adds(C::BASE_PAGE_SIZE().ilog2() as nat, shift as nat);
266 lemma_usize_shl_is_mul(C::BASE_PAGE_SIZE(), shift);
267 lemma_usize_pow2_shl_is_pow2(C::BASE_PAGE_SIZE(), shift);
268 lemma_pow2_pos(shift as nat);
269 lemma_mul_left_inequality(C::BASE_PAGE_SIZE() as int, 1, pow2(shift as nat) as int);
270 }
271 C::BASE_PAGE_SIZE() << (nr_subpage_per_huge::<C>().ilog2() as usize * (level as usize - 1))
272}
273
274#[verifier::inline]
275pub open spec fn nr_subpage_per_huge_spec<C: PagingConstsTrait>() -> usize {
276 C::BASE_PAGE_SIZE() / C::PTE_SIZE()
277}
278
279#[verifier::when_used_as_spec(nr_subpage_per_huge_spec)]
281pub fn nr_subpage_per_huge<C: PagingConstsTrait>() -> usize
282 returns
283 nr_subpage_per_huge_spec::<C>(),
284{
285 proof {
286 C::lemma_paging_consts_properties();
287 }
288 C::BASE_PAGE_SIZE() / C::PTE_SIZE()
289}
290
291pub const MAX_USERSPACE_VADDR: Vaddr = 0x0000_8000_0000_0000_usize - PAGE_SIZE;
302
303pub const KERNEL_VADDR_RANGE: Range<Vaddr> =
308 0xffff_8000_0000_0000_usize..0xffff_ffff_ffff_0000_usize;
309
310pub trait HasPaddr {
312 fn paddr(&self) -> Paddr;
314}
315
316pub const fn is_page_aligned(p: usize) -> bool {
318 (p & (PAGE_SIZE - 1)) == 0
319}
320
321}