1use vstd::{atomic::PermissionU64, prelude::*, simple_pptr::PointsTo};
36use vstd_extra::{
37 once::OnceImpl, ownership::*, prelude::*, resource_invariant::TrivialResourceInvariant,
38};
39
40use crate::specs::{
41 arch::*,
42 mm::{
43 frame::{
44 frame_specs::FrameRawPerms, mapping::group_page_meta, meta_owners::MetaSlotStorage,
45 meta_region_owners::MetaRegionOwners,
46 },
47 page_table::{nr_pte_index_bits_spec, pte_index_bit_offset_spec},
48 },
49};
50
51use core::{marker::PhantomData, ops::Range};
52
53pub(crate) mod kvirt_area;
55#[cfg(ktest)]
56mod test;
57
58use super::{
59 Paddr, PagingConstsTrait, Vaddr,
60 frame::{
61 Frame, Segment,
62 meta::{AnyFrameMeta, MetaPageMeta, MetaSlot, mapping},
63 },
64 page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags},
65 page_table::{PageTable, PageTableConfig},
66};
67use crate::mm::frame::DynFrame;
68use crate::mm::page_table::RCClone;
69use crate::{
70 arch::mm::{PageTableEntry, PagingConsts},
71 boot::memory_region::MemoryRegionType,
72 mm::{PagingLevel, largest_pages},
73 };
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
123#[cfg(not(target_arch = "loongarch64"))]
126pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
127
128#[cfg(target_arch = "loongarch64")]
129pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
130
131pub const LINEAR_MAPPING_VADDR_RANGE: Range<Vaddr> = LINEAR_MAPPING_BASE_VADDR..VMALLOC_BASE_VADDR;
132
133#[verus_verify(dual_spec, open)]
135#[verus_spec(
136 requires
137 pa + LINEAR_MAPPING_BASE_VADDR < usize::MAX,
138 returns
139 paddr_to_vaddr(pa),
140)]
141pub fn paddr_to_vaddr(pa: Paddr) -> usize {
142 pa + LINEAR_MAPPING_BASE_VADDR
144}
145
146#[allow(private_interfaces)]
151pub exec static KERNEL_PAGE_TABLE: OnceImpl<PageTable<KernelPtConfig>, TrivialResourceInvariant> =
152 OnceImpl::new(Ghost(TrivialResourceInvariant));
153
154#[verifier::allow(autoderive_clone_without_spec)]
155#[derive(Clone, Debug)]
156pub(crate) struct KernelPtConfig {}
157
158unsafe impl PageTableConfig for KernelPtConfig {
161 open spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize> {
162 256..512
163 }
164
165 proof fn lemma_page_table_config_constant_requirements() {
166 PageTableEntry::lemma_layout();
167 }
168
169 fn TOP_LEVEL_INDEX_RANGE() -> (r: Range<usize>) {
170 256..512
171 }
172
173 open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
174 false
175 }
176
177 fn TOP_LEVEL_CAN_UNMAP() -> (b: bool) {
178 false
179 }
180
181 type E = PageTableEntry;
182
183 type C = PagingConsts;
184
185 type Item = MappedItem;
186
187 type Perm = FrameRawPerms;
188
189 open spec fn perm_well_formed_with_region(
190 pa: Paddr,
191 perm: Tracked<Option<Self::Perm>>,
192 regions: MetaRegionOwners,
193 ) -> bool {
194 perm@ is Some ==> {
195 let idx = crate::specs::mm::frame::mapping::frame_to_index(pa);
196 let frame_perm = perm@->0;
197 &&& frame_perm.slot_perm == regions.slots[idx]
198 &&& frame_perm.metadata_perm.frac() == 1
199 &&& frame_perm.metadata_perm.id() == regions.slot_owners[idx].metadata_perm.id()
200 &&& MetaSlot::perms_related(*frame_perm.slot_perm, frame_perm.metadata_perm.resource())
201 }
202 }
203
204 proof fn lemma_none_perm_well_formed(pa: Paddr, regions: MetaRegionOwners) {
205 }
206
207 open spec fn item_into_raw_spec(item: Self::Item) -> (
208 Paddr,
209 PagingLevel,
210 PageProperty,
211 Tracked<Option<Self::Perm>>,
212 ) {
213 match item {
214 MappedItem::Tracked(frame, prop) => (
215 crate::mm::frame::meta::mapping::meta_to_frame(frame.slot_vaddr()),
216 1,
217 Self::encode_tracked_prop(prop),
218 Tracked(
219 Some(
220 FrameRawPerms {
221 slot_perm: frame.tracked_slot_perm@,
222 metadata_perm: frame.tracked_metadata_perm@->0,
223 },
224 ),
225 ),
226 ),
227 MappedItem::Untracked(pa, level, prop) => (
228 pa,
229 level,
230 Self::decode_tracked_prop(prop),
231 Tracked(None),
232 ),
233 }
234 }
235
236 #[verifier::external_body]
237 fn item_into_raw(item: Self::Item) -> (res: (
238 Paddr,
239 PagingLevel,
240 PageProperty,
241 Tracked<Option<Self::Perm>>,
242 )) {
243 match item {
244 MappedItem::Tracked(frame, mut prop) => {
245 proof_decl! {
246 let tracked raw_perm: FrameRawPerms;
247 }
248 debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
249 prop.flags = prop.flags | PageFlags::AVAIL1();
250 let level = frame.map_level();
251 let paddr = frame.into_raw();
252 proof_with!(=> Tracked(raw_perm));
253 (paddr, level, prop, Tracked(Some(raw_perm)))
254 },
255 MappedItem::Untracked(pa, level, mut prop) => {
256 debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
257 prop.flags = prop.flags - PageFlags::AVAIL1();
258 (pa, level, prop, Tracked(None))
259 },
260 }
261 }
262
263 open spec fn item_from_raw_spec(
264 paddr: Paddr,
265 level: PagingLevel,
266 prop: PageProperty,
267 perm: Tracked<Option<Self::Perm>>,
268 ) -> Self::Item {
269 if prop.flags.contains(PageFlags::AVAIL1()) {
270 MappedItem::Tracked(
271 Frame::<MetaSlotStorage> {
272 ptr: vstd::simple_pptr::PPtr(mapping::frame_to_meta(paddr), PhantomData),
273 _marker: PhantomData,
274 #[cfg(verus_keep_ghost_body)]
275 tracked_slot_perm: Tracked((perm@->0).slot_perm),
276 #[cfg(verus_keep_ghost_body)]
277 tracked_metadata_perm: Tracked(Some((perm@->0).metadata_perm)),
278 },
279 Self::decode_tracked_prop(prop),
280 )
281 } else {
282 MappedItem::Untracked(paddr, level, prop)
283 }
284 }
285
286 #[verifier::external_body]
287 unsafe fn item_from_raw(
288 paddr: Paddr,
289 level: PagingLevel,
290 prop: PageProperty,
291 Tracked(perm): Tracked<Option<Self::Perm>>,
292 ) -> Self::Item {
293 if prop.flags.contains(PageFlags::AVAIL1()) {
294 debug_assert_eq!(level, 1);
295 let mut item_prop = prop;
297 item_prop.flags = item_prop.flags - PageFlags::AVAIL1();
298 let tracked raw_perm = perm.tracked_unwrap();
299 proof_with!(Tracked(raw_perm));
301 let frame = unsafe { Frame::<MetaSlotStorage>::from_raw(paddr) };
302 MappedItem::Tracked(frame, item_prop)
303 } else {
304 MappedItem::Untracked(paddr, level, prop)
305 }
306 }
307
308 proof fn lemma_item_into_raw_roundtrip(
309 pa: Paddr,
310 level: PagingLevel,
311 prop: PageProperty,
312 perm: Tracked<Option<Self::Perm>>,
313 ) {
314 broadcast use group_page_meta;
315
316 assert(Self::raw_item_well_formed((pa, level, prop, perm)));
317 prop.lemma_avail1_tag_encoding();
318 if prop.flags.contains(PageFlags::AVAIL1()) {
319 assert(Self::item_from_raw(pa, level, prop, perm) is Tracked);
320 assert(perm@ is Some);
321 } else {
322 assert(Self::item_from_raw(pa, level, prop, perm) is Untracked);
323 assert(perm@ is None);
324 }
325 }
326
327 proof fn lemma_item_from_raw_roundtrip(
328 item: Self::Item,
329 paddr: Paddr,
330 level: PagingLevel,
331 prop: PageProperty,
332 perm: Tracked<Option<Self::Perm>>,
333 ) {
334 broadcast use group_page_meta;
335
336 match item {
337 MappedItem::Tracked(frame, prop_actual) => {
338 assert(Self::item_well_formed(item));
339 prop_actual.lemma_avail1_tag_encoding();
340 },
341 MappedItem::Untracked(_, _, prop_actual) => {
342 assert(Self::item_well_formed(item));
343 prop_actual.lemma_avail1_tag_encoding();
344 },
345 }
346 }
347
348 open spec fn item_well_formed(item: Self::Item) -> bool {
349 match item {
350 MappedItem::Tracked(frame, prop) => {
351 &&& !prop.flags.contains(PageFlags::AVAIL1())
352 &&& frame.inv()
353 },
354 MappedItem::Untracked(_, _, prop) => !prop.flags.contains(PageFlags::AVAIL1()),
355 }
356 }
357
358 open spec fn raw_item_well_formed(
359 item: (Paddr, PagingLevel, PageProperty, Tracked<Option<Self::Perm>>),
360 ) -> bool {
361 let (pa, level, prop, perm) = item;
362 &&& (prop.flags.contains(PageFlags::AVAIL1()) <==> perm@ is Some)
363 &&& prop.flags.contains(PageFlags::AVAIL1()) ==> {
364 &&& level == 1
365 &&& (perm@->0).slot_perm.addr() == mapping::frame_to_meta(pa)
366 &&& (perm@->0).slot_perm.is_init()
367 &&& (perm@->0).metadata_perm.frac() == 1
368 &&& MetaSlot::perms_related(*(perm@->0).slot_perm, (perm@->0).metadata_perm.resource())
369 }
370 }
371
372 proof fn lemma_perm_well_formed_with_region_preserved(
373 pa: Paddr,
374 perm: Tracked<Option<Self::Perm>>,
375 old_regions: MetaRegionOwners,
376 new_regions: MetaRegionOwners,
377 ) {
378 }
379
380 proof fn lemma_raw_item_well_formed_preserved(
381 pa: Paddr,
382 level: PagingLevel,
383 old_prop: PageProperty,
384 new_prop: PageProperty,
385 perm: Tracked<Option<Self::Perm>>,
386 ) {
387 }
388
389 proof fn lemma_raw_item_well_formed_split(
390 pa: Paddr,
391 level: PagingLevel,
392 prop: PageProperty,
393 child_pa: Paddr,
394 child_idx: usize,
395 perm: Tracked<Option<Self::Perm>>,
396 ) {
397 assert(<PageTableEntry as crate::mm::page_table::PageTableEntryTrait>::new_page_req(
398 pa,
399 level,
400 prop,
401 ));
402 assert(<PageTableEntry as crate::mm::page_table::PageTableEntryTrait>::new_page_req(
403 child_pa,
404 (level - 1) as PagingLevel,
405 prop,
406 ));
407 }
408
409 proof fn lemma_huge_raw_item_untracked(
410 pa: Paddr,
411 level: PagingLevel,
412 prop: PageProperty,
413 perm: Tracked<Option<Self::Perm>>,
414 ) {
415 }
416
417 proof fn lemma_item_from_raw_well_formed(
418 pa: Paddr,
419 level: PagingLevel,
420 prop: PageProperty,
421 perm: Tracked<Option<Self::Perm>>,
422 ) {
423 broadcast use group_page_meta;
424
425 prop.lemma_avail1_tag_encoding();
426 }
427
428 proof fn lemma_clone_ensures_concrete(
429 item: Self::Item,
430 pa: Paddr,
431 old_regions: MetaRegionOwners,
432 new_regions: MetaRegionOwners,
433 res: Self::Item,
434 ) {
435 use crate::specs::mm::frame::mapping::{frame_to_index, meta_to_index};
436
437 match item {
438 MappedItem::Tracked(frame, _) => {
439 let frame_idx = meta_to_index(frame.slot_vaddr());
440 assert(frame.index() == frame_to_index(pa));
441 assert(<MappedItem as RCClone>::clone_ensures(item, old_regions, new_regions, res));
442 },
443 MappedItem::Untracked(_, _, _) => {},
444 }
445 }
446
447 proof fn lemma_clone_requires_concrete(
448 item: Self::Item,
449 pa: Paddr,
450 level: PagingLevel,
451 prop: PageProperty,
452 regions: MetaRegionOwners,
453 ) {
454 use crate::specs::mm::frame::mapping::frame_to_index;
455
456 use crate::mm::frame::meta::mapping::{frame_to_meta, meta_to_frame};
457 use crate::mm::frame::meta::{REF_COUNT_MAX, REF_COUNT_UNUSED};
458 broadcast use group_page_meta;
459
460 let perm = Self::item_into_raw(item).3;
461 Self::lemma_item_from_raw_well_formed(pa, level, prop, perm);
462 match item {
463 MappedItem::Tracked(frame, _) => {
464 crate::specs::mm::frame::mapping::lemma_paddr_to_meta_biinjective(pa);
465 regions.lemma_contains_valid_frame_paddr(pa);
466 },
467 MappedItem::Untracked(_, _, _) => {},
468 }
469 }
470}
471
472impl KernelPtConfig {
473 pub open spec fn encode_tracked_prop(prop: PageProperty) -> PageProperty {
475 PageProperty { flags: prop.flags.union(PageFlags::AVAIL1()), ..prop }
476 }
477
478 pub open spec fn decode_tracked_prop(prop: PageProperty) -> PageProperty {
480 PageProperty { flags: prop.flags.difference(PageFlags::AVAIL1()), ..prop }
481 }
482}
483
484pub enum MappedItem {
493 Tracked(DynFrame, PageProperty),
494 Untracked(Paddr, PagingLevel, PageProperty),
495}
496
497impl RCClone for MappedItem {
498 open spec fn clone_requires(self, perm: MetaRegionOwners) -> bool {
499 match self {
500 MappedItem::Tracked(frame, _) => frame.clone_requires(perm),
501 MappedItem::Untracked(_, _, _) => perm.inv(),
502 }
503 }
504
505 open spec fn clone_ensures(
506 self,
507 old_perm: MetaRegionOwners,
508 new_perm: MetaRegionOwners,
509 res: Self,
510 ) -> bool {
511 match (self, res) {
512 (MappedItem::Tracked(frame, prop), MappedItem::Tracked(res_frame, res_prop)) => {
513 &&& prop == res_prop
514 &&& frame.clone_ensures(old_perm, new_perm, res_frame)
515 },
516 (
517 MappedItem::Untracked(pa, level, prop),
518 MappedItem::Untracked(res_pa, res_level, res_prop),
519 ) => {
520 &&& pa == res_pa
521 &&& level == res_level
522 &&& prop == res_prop
523 &&& old_perm == new_perm
524 },
525 _ => false,
526 }
527 }
528
529 #[verifier::external_body]
530 fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
531 unimplemented!();
532 }
533}
534
535}