1use core::{marker::PhantomData, ops::Range};
36use vstd::atomic::PermissionU64;
37use vstd::prelude::*;
38use vstd::simple_pptr::PointsTo;
39
40use crate::sync::{OnceImpl, TrivialPred};
42pub(crate) mod kvirt_area;
43#[cfg(ktest)]
44mod test;
45
46use super::{
47 Paddr, PagingConstsTrait, Vaddr,
48 frame::{
49 Frame, Segment,
50 meta::{AnyFrameMeta, MetaPageMeta, MetaSlot, mapping},
51 },
52 page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
53 page_table::{PageTable, PageTableConfig},
54};
55use crate::mm::frame::DynFrame;
56use crate::mm::page_table::RCClone;
57use crate::specs::arch::*;
58use crate::specs::mm::{
59 frame::{
60 mapping::group_page_meta,
61 meta_owners::{MetaPerm, MetaSlotStorage},
62 meta_region_owners::MetaRegionOwners,
63 },
64 page_table::{nr_pte_index_bits_spec, pte_index_bit_offset_spec},
65};
66use crate::{
67 arch::mm::{PageTableEntry, PagingConsts},
68 boot::memory_region::MemoryRegionType,
69 mm::{PagingLevel, largest_pages},
70 };
72
73use vstd_extra::ownership::*;
74use vstd_extra::prelude::*;
75
76verus! {
77
78pub const ADDR_WIDTH_SHIFT: isize = 48 - 48;
82
83#[cfg(not(target_arch = "loongarch64"))]
86pub const KERNEL_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
87
88#[cfg(target_arch = "loongarch64")]
89pub const KERNEL_BASE_VADDR: Vaddr = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
90
91pub const KERNEL_END_VADDR: Vaddr = 0xffff_ffff_ffff_0000 << ADDR_WIDTH_SHIFT;
93
94#[cfg(target_arch = "x86_64")]
105const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_8000_0000 << ADDR_WIDTH_SHIFT;
106
107#[cfg(target_arch = "riscv64")]
108const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_0000_0000 << ADDR_WIDTH_SHIFT;
109
110#[cfg(target_arch = "loongarch64")]
111const KERNEL_CODE_BASE_VADDR: usize = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
112
113pub const FRAME_METADATA_CAP_VADDR: Vaddr = 0xffff_e100_0000_0000 << ADDR_WIDTH_SHIFT;
114
115pub const FRAME_METADATA_BASE_VADDR: Vaddr = 0xffff_e000_0000_0000 << ADDR_WIDTH_SHIFT;
116
117pub const FRAME_METADATA_RANGE: Range<Vaddr> = 0xffff_e000_0000_0000..0xffff_e100_0000_0000;
118
119pub const VMALLOC_BASE_VADDR: Vaddr = 0xffff_c000_0000_0000 << ADDR_WIDTH_SHIFT;
120
121pub const VMALLOC_VADDR_RANGE: Range<Vaddr> = VMALLOC_BASE_VADDR..FRAME_METADATA_BASE_VADDR;
122
123pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
126
127pub const LINEAR_MAPPING_VADDR_RANGE: Range<Vaddr> = LINEAR_MAPPING_BASE_VADDR..VMALLOC_BASE_VADDR;
128
129pub open spec fn paddr_to_vaddr_spec(pa: Paddr) -> usize {
139 (pa + LINEAR_MAPPING_BASE_VADDR) as usize
140}
141
142#[verifier::when_used_as_spec(paddr_to_vaddr_spec)]
143pub fn paddr_to_vaddr(pa: Paddr) -> usize
144 requires
145 pa + LINEAR_MAPPING_BASE_VADDR < usize::MAX,
146 returns
147 paddr_to_vaddr_spec(pa),
148{
149 pa + LINEAR_MAPPING_BASE_VADDR
151}
152
153#[allow(private_interfaces)]
158pub exec static KERNEL_PAGE_TABLE: OnceImpl<PageTable<KernelPtConfig>, TrivialPred> = OnceImpl::new(
159 Ghost(TrivialPred),
160);
161
162#[verifier::allow(autoderive_clone_without_spec)]
163#[derive(Clone, Debug)]
164pub(crate) struct KernelPtConfig {}
165
166unsafe impl PageTableConfig for KernelPtConfig {
169 open spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize> {
170 256..512
171 }
172
173 open spec fn LEADING_BITS_spec() -> usize {
174 0xffff
175 }
176
177 proof fn lemma_page_table_config_constant_requirements() {
178 use crate::mm::nr_subpage_per_huge;
179 use vstd::arithmetic::power2::{lemma2_to64, lemma2_to64_rest, lemma_pow2_adds, pow2};
180 Self::C::lemma_paging_consts_properties();
181 PageTableEntry::lemma_layout();
182 lemma2_to64();
183 lemma2_to64_rest();
184 vstd::layout::unsigned_int_max_values();
185 lemma_usize_pow2_ilog2(12);
186 lemma_usize_pow2_ilog2(9);
187 lemma_pow2_adds(9, 39);
188 lemma_pow2_adds(8, 39);
189
190 assert((256 * pow2(39) as int) / (pow2(47) as int) == 1);
191 lemma_pow2_adds(16, 48);
192 }
193
194 fn TOP_LEVEL_INDEX_RANGE() -> (r: Range<usize>) {
195 256..512
196 }
197
198 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
199 false
200 }
201
202 fn TOP_LEVEL_CAN_UNMAP() -> (b: bool) {
203 false
204 }
205
206 open spec fn LOCKED_END_BOUND_spec() -> int {
209 FRAME_METADATA_BASE_VADDR as int
210 }
211
212 type E = PageTableEntry;
213
214 type C = PagingConsts;
215
216 type Item = MappedItem;
217
218 open spec fn item_into_raw_spec(item: Self::Item) -> (Paddr, PagingLevel, PageProperty) {
219 match item {
220 MappedItem::Tracked(frame, prop) => (
221 crate::mm::frame::meta::mapping::meta_to_frame(frame.ptr.addr()),
222 1,
223 Self::encode_tracked_prop(prop),
224 ),
225 MappedItem::Untracked(pa, level, prop) => (pa, level, Self::decode_tracked_prop(prop)),
226 }
227 }
228
229 #[verifier::external_body]
230 fn item_into_raw(item: Self::Item) -> (res: (Paddr, PagingLevel, PageProperty)) {
231 match item {
232 MappedItem::Tracked(frame, mut prop) => {
233 debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
234 prop.flags = prop.flags | PageFlags::AVAIL1();
235 let level = frame.map_level();
236 let paddr = frame.into_raw();
237 (paddr, level, prop)
238 },
239 MappedItem::Untracked(pa, level, mut prop) => {
240 debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
241 prop.flags = prop.flags - PageFlags::AVAIL1();
242 (pa, level, prop)
243 },
244 }
245 }
246
247 open spec fn item_from_raw_spec(
248 paddr: Paddr,
249 level: PagingLevel,
250 prop: PageProperty,
251 ) -> Self::Item {
252 if prop.flags.contains(PageFlags::AVAIL1()) {
253 MappedItem::Tracked(
254 Frame::<MetaSlotStorage> {
255 ptr: vstd::simple_pptr::PPtr(mapping::frame_to_meta(paddr), PhantomData),
256 _marker: PhantomData,
257 },
258 Self::decode_tracked_prop(prop),
259 )
260 } else {
261 MappedItem::Untracked(paddr, level, prop)
262 }
263 }
264
265 #[verifier::external_body]
266 unsafe fn item_from_raw(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item {
267 if prop.flags.contains(PageFlags::AVAIL1()) {
268 debug_assert_eq!(level, 1);
269 let mut item_prop = prop;
271 item_prop.flags = item_prop.flags - PageFlags::AVAIL1();
272 let frame = unsafe { Frame::<MetaSlotStorage>::from_raw(paddr) };
274 MappedItem::Tracked(frame, item_prop)
275 } else {
276 MappedItem::Untracked(paddr, level, prop)
277 }
278 }
279
280 proof fn lemma_item_into_raw_roundtrip(pa: Paddr, level: PagingLevel, prop: PageProperty) {
281 broadcast use group_page_meta;
282
283 assert(Self::raw_item_well_formed(pa, level, prop));
284 Self::lemma_item_from_raw_well_formed(pa, level, prop);
285 prop.lemma_avail1_tag_encoding();
286 }
287
288 proof fn lemma_item_from_raw_roundtrip(
289 item: Self::Item,
290 paddr: Paddr,
291 level: PagingLevel,
292 prop: PageProperty,
293 ) {
294 broadcast use group_page_meta;
295
296 match item {
297 MappedItem::Tracked(frame, prop_actual) => {
298 assert(Self::item_well_formed(item));
299 prop_actual.lemma_avail1_tag_encoding();
300 },
301 MappedItem::Untracked(_, _, prop_actual) => {
302 assert(Self::item_well_formed(item));
303 prop_actual.lemma_avail1_tag_encoding();
304 },
305 }
306 }
307
308 open spec fn tracked(item: Self::Item) -> bool {
309 item is Tracked
312 }
313
314 open spec fn item_well_formed(item: Self::Item) -> bool {
315 match item {
316 MappedItem::Tracked(frame, prop) => {
317 &&& !prop.flags.contains(PageFlags::AVAIL1())
318 &&& frame.inv()
319 },
320 MappedItem::Untracked(_, _, prop) => !prop.flags.contains(PageFlags::AVAIL1()),
321 }
322 }
323
324 open spec fn raw_item_well_formed(_pa: Paddr, level: PagingLevel, prop: PageProperty) -> bool {
325 prop.flags.contains(PageFlags::AVAIL1()) ==> level == 1
326 }
327
328 proof fn lemma_raw_item_well_formed_preserved(
329 pa: Paddr,
330 level: PagingLevel,
331 old_prop: PageProperty,
332 new_prop: PageProperty,
333 ) {
334 }
335
336 proof fn lemma_raw_item_well_formed_split(
337 pa: Paddr,
338 level: PagingLevel,
339 prop: PageProperty,
340 child_pa: Paddr,
341 child_idx: usize,
342 ) {
343 assert(<PageTableEntry as crate::mm::page_table::PageTableEntryTrait>::new_page_req(
344 pa,
345 level,
346 prop,
347 ));
348 assert(<PageTableEntry as crate::mm::page_table::PageTableEntryTrait>::new_page_req(
349 child_pa,
350 (level - 1) as PagingLevel,
351 prop,
352 ));
353 }
354
355 proof fn lemma_item_from_raw_well_formed(pa: Paddr, level: PagingLevel, prop: PageProperty) {
356 broadcast use group_page_meta;
357
358 prop.lemma_avail1_tag_encoding();
359 if prop.flags.contains(PageFlags::AVAIL1()) {
360 let item = Self::item_from_raw_spec(pa, level, prop);
361 assert(Self::item_well_formed(item));
362 } else {
363 let item = Self::item_from_raw_spec(pa, level, prop);
364 assert(Self::item_well_formed(item));
365 }
366 }
367
368 proof fn lemma_clone_ensures_concrete(
369 item: Self::Item,
370 pa: Paddr,
371 old_regions: MetaRegionOwners,
372 new_regions: MetaRegionOwners,
373 res: Self::Item,
374 ) {
375 use crate::mm::frame::meta::mapping::meta_to_frame;
376 use crate::specs::mm::frame::mapping::frame_to_index;
377
378 match item {
379 MappedItem::Tracked(frame, _) => {
380 let frame_idx = frame_to_index(meta_to_frame(frame.ptr.addr()));
381 assert(<MappedItem as RCClone>::clone_ensures(item, old_regions, new_regions, res));
382 },
383 MappedItem::Untracked(_, _, _) => {},
384 }
385 }
386
387 proof fn lemma_clone_requires_concrete(
388 item: Self::Item,
389 pa: Paddr,
390 level: PagingLevel,
391 prop: PageProperty,
392 regions: MetaRegionOwners,
393 ) {
394 use crate::mm::frame::meta::mapping::meta_to_frame;
395 broadcast use group_page_meta;
396
397 Self::lemma_item_from_raw_well_formed(pa, level, prop);
398 }
399}
400
401impl KernelPtConfig {
402 pub open spec fn encode_tracked_prop(prop: PageProperty) -> PageProperty {
404 PageProperty { flags: prop.flags.union(PageFlags::AVAIL1()), ..prop }
405 }
406
407 pub open spec fn decode_tracked_prop(prop: PageProperty) -> PageProperty {
409 PageProperty { flags: prop.flags.difference(PageFlags::AVAIL1()), ..prop }
410 }
411}
412
413pub enum MappedItem {
422 Tracked(DynFrame, PageProperty),
423 Untracked(Paddr, PagingLevel, PageProperty),
424}
425
426impl RCClone for MappedItem {
427 open spec fn clone_requires(self, perm: MetaRegionOwners) -> bool {
428 match self {
429 MappedItem::Tracked(frame, _) => frame.clone_requires(perm),
430 MappedItem::Untracked(_, _, _) => perm.inv(),
431 }
432 }
433
434 open spec fn clone_ensures(
435 self,
436 old_perm: MetaRegionOwners,
437 new_perm: MetaRegionOwners,
438 res: Self,
439 ) -> bool {
440 match (self, res) {
441 (
442 MappedItem::Tracked(frame, _),
443 MappedItem::Tracked(res_frame, _),
444 ) => frame.clone_ensures(old_perm, new_perm, res_frame),
445 (MappedItem::Untracked(_, _, _), _) => old_perm == new_perm,
446 _ => true,
447 }
448 }
449
450 #[verifier::external_body]
451 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
452 unimplemented!();
453 }
454}
455
456}