ostd/mm/page_table/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2use vstd::arithmetic::power2::*;
3use vstd::prelude::*;
4use vstd::std_specs::clone::*;
5
6use vstd_extra::prelude::lemma_usize_ilog2_ordered;
7
8use core::{
9    fmt::Debug,
10    intrinsics::transmute_unchecked,
11    ops::{Range, RangeInclusive},
12    sync::atomic::{AtomicUsize, Ordering},
13};
14
15use super::{
16    lemma_nr_subpage_per_huge_bounded,
17    //    kspace::KernelPtConfig,
18    nr_subpage_per_huge,
19    page_prop::PageProperty,
20    Paddr,
21    //    vm_space::UserPtConfig,
22    PagingConstsTrait,
23    PagingLevel,
24    //    PodOnce,
25    Vaddr,
26};
27
28use crate::specs::mm::page_table::*;
29
30use crate::specs::arch::mm::*;
31use crate::specs::arch::paging_consts::PagingConsts;
32use crate::specs::mm::page_table::cursor::*;
33use crate::specs::task::InAtomicMode;
34
35mod node;
36pub use node::*;
37mod cursor;
38
39pub(crate) use cursor::*;
40
41#[cfg(ktest)]
42mod test;
43
44//pub(crate) mod boot_pt;
45
46verus! {
47
48#[derive(Clone, Copy, PartialEq, Eq, Debug)]
49pub enum PageTableError {
50    /// The provided virtual address range is invalid.
51    InvalidVaddrRange(Vaddr, Vaddr),
52    /// The provided virtual address is invalid.
53    InvalidVaddr(Vaddr),
54    /// Using virtual address not aligned.
55    UnalignedVaddr,
56}
57
58/// The configurations of a page table.
59///
60/// It abstracts away both the usage and the architecture specifics from the
61/// general page table implementation. For examples:
62///  - the managed virtual address range;
63///  - the trackedness of physical mappings;
64///  - the PTE layout;
65///  - the number of page table levels, etc.
66///
67/// # Safety
68///
69/// The implementor must ensure that the `item_into_raw` and `item_from_raw`
70/// are implemented correctly so that:
71///  - `item_into_raw` consumes the ownership of the item;
72///  - if the provided raw form matches the item that was consumed by
73///    `item_into_raw`, `item_from_raw` restores the exact item that was
74///    consumed by `item_into_raw`.
75pub unsafe trait PageTableConfig: Clone + Debug + Send + Sync + 'static {
76    /// The index range at the top level (`C::NR_LEVELS()`) page table.
77    ///
78    /// When configured with this value, the [`PageTable`] instance will only
79    /// be allowed to manage the virtual address range that is covered by
80    /// this range. The range can be smaller than the actual allowed range
81    /// specified by the hardware MMU (limited by `C::ADDRESS_WIDTH`).
82    spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize>;
83
84    fn TOP_LEVEL_INDEX_RANGE() -> (r: Range<usize>)
85        ensures
86            r == Self::TOP_LEVEL_INDEX_RANGE_spec(),
87    ;
88
89    /// If we can remove the top-level page table entries.
90    ///
91    /// This is for the kernel page table, whose second-top-level page
92    /// tables need `'static` lifetime to be shared with user page tables.
93    /// Other page tables do not need to set this to `false`.
94    open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
95        true
96    }
97
98    fn TOP_LEVEL_CAN_UNMAP() -> (b: bool)
99        ensures
100            b == Self::TOP_LEVEL_CAN_UNMAP_spec(),
101    ;
102
103    /// The type of the page table entry.
104    type E: PageTableEntryTrait;
105
106    /// The paging constants.
107    type C: PagingConstsTrait;
108
109    proof fn axiom_nr_subpage_per_huge_eq_nr_entries()
110        ensures
111            Self::C::BASE_PAGE_SIZE() / Self::C::PTE_SIZE() == NR_ENTRIES,
112    ;
113
114    /// The item that can be mapped into the virtual memory space using the
115    /// page table.
116    ///
117    /// Usually, this item is a [`crate::mm::Frame`], which we call a "tracked"
118    /// frame. The page table can also do "untracked" mappings that only maps
119    /// to certain physical addresses without tracking the ownership of the
120    /// mapped physical frame. The user of the page table APIs can choose by
121    /// defining this type and the corresponding methods [`item_into_raw`] and
122    /// [`item_from_raw`].
123    ///
124    /// [`item_from_raw`]: PageTableConfig::item_from_raw
125    /// [`item_into_raw`]: PageTableConfig::item_into_raw
126    type Item: Clone;
127
128    /// Consumes the item and returns the physical address, the paging level,
129    /// and the page property.
130    ///
131    /// The ownership of the item will be consumed, i.e., the item will be
132    /// forgotten after this function is called.
133    spec fn item_into_raw_spec(item: Self::Item) -> (Paddr, PagingLevel, PageProperty);
134
135    #[verifier::when_used_as_spec(item_into_raw_spec)]
136    fn item_into_raw(item: Self::Item) -> (res: (Paddr, PagingLevel, PageProperty))
137        ensures
138            1 <= res.1 <= NR_LEVELS,
139            res == Self::item_into_raw_spec(item),
140    ;
141
142    /// Restores the item from the physical address and the paging level.
143    ///
144    /// There could be transformations after [`PageTableConfig::item_into_raw`]
145    /// and before [`PageTableConfig::item_from_raw`], which include:
146    ///  - splitting and coalescing the items, for example, splitting one item
147    ///    into 512 `level - 1` items with and contiguous physical addresses;
148    ///  - protecting the items, for example, changing the page property.
149    ///
150    /// Splitting and coalescing maintains ownership rules, i.e., if one
151    /// physical address is within the range of one item, after splitting/
152    /// coalescing, there should be exactly one item that contains the address.
153    ///
154    /// # Safety
155    ///
156    /// The caller must ensure that:
157    ///  - the physical address and the paging level represent a page table
158    ///    item or part of it (as described above);
159    ///  - either the ownership of the item is properly transferred to the
160    ///    return value, or the return value is wrapped in a
161    ///    [`core::mem::ManuallyDrop`] that won't outlive the original item.
162    ///
163    /// A concrete trait implementation may require the caller to ensure that
164    ///  - the [`super::PageFlags::AVAIL1`] flag is the same as that returned
165    ///    from [`PageTableConfig::item_into_raw`].
166    spec fn item_from_raw_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item;
167
168    #[verifier::when_used_as_spec(item_from_raw_spec)]
169    fn item_from_raw(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self::Item
170        returns
171            Self::item_from_raw_spec(paddr, level, prop),
172    ;
173
174    proof fn item_roundtrip(item: Self::Item, paddr: Paddr, level: PagingLevel, prop: PageProperty)
175        ensures
176            Self::item_into_raw_spec(item) == (paddr, level, prop) <==> Self::item_from_raw_spec(
177                paddr,
178                level,
179                prop,
180            ) == item,
181    ;
182}
183
184// Implement it so that we can comfortably use low level functions
185// like `page_size::<C>` without typing `C::C` everywhere.
186impl<C: PageTableConfig> PagingConstsTrait for C {
187    open spec fn BASE_PAGE_SIZE_spec() -> usize {
188        C::C::BASE_PAGE_SIZE_spec()
189    }
190
191    fn BASE_PAGE_SIZE() -> usize {
192        C::C::BASE_PAGE_SIZE()
193    }
194
195    open spec fn NR_LEVELS_spec() -> PagingLevel {
196        C::C::NR_LEVELS_spec()
197    }
198
199    fn NR_LEVELS() -> PagingLevel {
200        C::C::NR_LEVELS()
201    }
202
203    open spec fn HIGHEST_TRANSLATION_LEVEL_spec() -> PagingLevel {
204        C::C::HIGHEST_TRANSLATION_LEVEL_spec()
205    }
206
207    fn HIGHEST_TRANSLATION_LEVEL() -> PagingLevel {
208        C::C::HIGHEST_TRANSLATION_LEVEL()
209    }
210
211    open spec fn PTE_SIZE_spec() -> usize {
212        C::C::PTE_SIZE_spec()
213    }
214
215    fn PTE_SIZE() -> usize {
216        C::C::PTE_SIZE()
217    }
218
219    open spec fn ADDRESS_WIDTH_spec() -> usize {
220        C::C::ADDRESS_WIDTH_spec()
221    }
222
223    fn ADDRESS_WIDTH() -> usize {
224        C::C::ADDRESS_WIDTH()
225    }
226
227    open spec fn VA_SIGN_EXT_spec() -> bool {
228        C::C::VA_SIGN_EXT_spec()
229    }
230
231    fn VA_SIGN_EXT() -> bool {
232        C::C::VA_SIGN_EXT()
233    }
234
235    proof fn lemma_BASE_PAGE_SIZE_properties()
236        ensures
237            0 < Self::BASE_PAGE_SIZE_spec(),
238            is_pow2(Self::BASE_PAGE_SIZE_spec() as int),
239    {
240        admit()
241    }
242
243    proof fn lemma_PTE_SIZE_properties()
244        ensures
245            0 < Self::PTE_SIZE_spec() <= Self::BASE_PAGE_SIZE(),
246            is_pow2(Self::PTE_SIZE_spec() as int),
247    {
248        admit()
249    }
250}
251
252/// The interface for defining architecture-specific page table entries.
253///
254/// Note that a default PTE should be a PTE that points to nothing.
255pub trait PageTableEntryTrait: Clone + Copy + Debug + Sized + Send + Sync + 'static {
256    spec fn default_spec() -> Self;
257
258    /// For implement `Default` trait.
259    #[verifier::when_used_as_spec(default_spec)]
260    fn default() -> (res: Self)
261        ensures
262            res == Self::default_spec(),
263    ;
264
265    /// Create a set of new invalid page table flags that indicates an absent page.
266    ///
267    /// Note that currently the implementation requires an all zero PTE to be an absent PTE.
268    spec fn new_absent_spec() -> Self;
269
270    #[verifier(when_used_as_spec(new_absent_spec))]
271    fn new_absent() -> (res: Self)
272        ensures
273            res == Self::new_absent_spec(),
274            res.paddr() % PAGE_SIZE == 0,
275            res.paddr() < MAX_PADDR,
276    ;
277
278    /// If the flags are present with valid mappings.
279    spec fn is_present_spec(&self) -> bool;
280
281    #[verifier::when_used_as_spec(is_present_spec)]
282    fn is_present(&self) -> (res: bool)
283        ensures
284            res == self.is_present_spec(),
285    ;
286
287    /// Create a new PTE with the given physical address and flags that map to a page.
288    spec fn new_page_spec(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> Self;
289
290    #[verifier::when_used_as_spec(new_page_spec)]
291    fn new_page(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res: Self)
292        requires
293            paddr % PAGE_SIZE == 0,
294            paddr < MAX_PADDR,
295        ensures
296            res == Self::new_page_spec(paddr, level, prop),
297            res.paddr() == paddr,
298            res.paddr() % PAGE_SIZE == 0,
299            res.paddr() < MAX_PADDR,
300    ;
301
302    /// Create a new PTE that map to a child page table.
303    spec fn new_pt_spec(paddr: Paddr) -> Self;
304
305    #[verifier::when_used_as_spec(new_pt_spec)]
306    fn new_pt(paddr: Paddr) -> (res: Self)
307        requires
308            paddr % PAGE_SIZE == 0,
309            paddr < MAX_PADDR,
310        ensures
311            res == Self::new_pt_spec(paddr),
312            res.paddr() == paddr,
313            res.paddr() % PAGE_SIZE == 0,
314            res.paddr() < MAX_PADDR,
315    ;
316
317    proof fn new_properties()
318        ensures
319            !Self::new_absent_spec().is_present(),
320            forall|paddr: Paddr, level: PagingLevel, prop: PageProperty|
321                #![trigger Self::new_page_spec(paddr, level, prop)]
322                {
323                    &&& Self::new_page_spec(paddr, level, prop).is_present()
324                    &&& Self::new_page_spec(paddr, level, prop).paddr() == paddr
325                    &&& Self::new_page_spec(paddr, level, prop).prop() == prop
326                    &&& Self::new_page_spec(paddr, level, prop).is_last(level)
327                },
328            forall|paddr: Paddr|
329                #![trigger Self::new_pt_spec(paddr)]
330                {
331                    &&& Self::new_pt_spec(paddr).is_present()
332                    &&& Self::new_pt_spec(paddr).paddr() == paddr
333                    &&& forall|level: PagingLevel| !Self::new_pt_spec(paddr).is_last(level)
334                },
335    ;
336
337    /// Get the physical address from the PTE.
338    /// The physical address recorded in the PTE is either:
339    /// - the physical address of the next level page table;
340    /// - or the physical address of the page it maps to.
341    spec fn paddr_spec(&self) -> Paddr;
342
343    #[verifier::when_used_as_spec(paddr_spec)]
344    fn paddr(&self) -> (res: Paddr)
345        ensures
346            res == self.paddr_spec(),
347    ;
348
349    spec fn prop_spec(&self) -> PageProperty;
350
351    #[verifier::when_used_as_spec(prop_spec)]
352    fn prop(&self) -> (res: PageProperty)
353        ensures
354            res == self.prop_spec(),
355    ;
356
357    /// Set the page property of the PTE.
358    ///
359    /// This will be only done if the PTE is present. If not, this method will
360    /// do nothing.
361    spec fn set_prop_spec(&self, prop: PageProperty) -> Self;
362
363    fn set_prop(&mut self, prop: PageProperty)
364        ensures
365            old(self).set_prop_spec(prop) == *self,
366    ;
367
368    proof fn set_prop_properties(self, prop: PageProperty)
369        ensures
370            self.set_prop_spec(prop).prop() == prop,
371            self.set_prop_spec(prop).paddr() == self.paddr(),
372            self.is_present() ==> self.set_prop_spec(prop).is_present(),
373            forall|level: PagingLevel|
374                #![trigger self.is_last(level)]
375                self.is_last(level) ==> self.set_prop_spec(prop).is_last(level),
376    ;
377
378    /// If the PTE maps a page rather than a child page table.
379    ///
380    /// The level of the page table the entry resides is given since architectures
381    /// like amd64 only uses a huge bit in intermediate levels.
382    spec fn is_last_spec(&self, level: PagingLevel) -> bool;
383
384    #[verifier::when_used_as_spec(is_last_spec)]
385    fn is_last(&self, level: PagingLevel) -> (b: bool)
386        ensures
387            b == self.is_last_spec(level),
388    ;
389
390    /// Converts the PTE into its corresponding `usize` value.
391    spec fn as_usize_spec(self) -> usize;
392
393    #[verifier::external_body]
394    #[verifier::when_used_as_spec(as_usize_spec)]
395    fn as_usize(self) -> (res: usize)
396        ensures
397            res == self.as_usize_spec(),
398    {
399        unimplemented!()
400        // SAFETY: `Self` is `Pod` and has the same memory representation as `usize`.
401        //        unsafe { transmute_unchecked(self) }
402
403    }
404
405    /// Converts a usize `pte_raw` into a PTE.
406    #[verifier::external_body]
407    fn from_usize(pte_raw: usize) -> Self {
408        unimplemented!()
409        // SAFETY: `Self` is `Pod` and has the same memory representation as `usize`.
410        //        unsafe { transmute_unchecked(pte_raw) }
411
412    }
413}
414
415/// A handle to a page table.
416/// A page table can track the lifetime of the mapped physical pages.
417pub struct PageTable<C: PageTableConfig> {
418    pub root: PageTableNode<C>,
419}
420
421#[verifier::inline]
422pub open spec fn nr_pte_index_bits_spec<C: PagingConstsTrait>() -> usize {
423    nr_subpage_per_huge::<C>().ilog2() as usize
424}
425
426/// The number of virtual address bits used to index a PTE in a page.
427#[inline(always)]
428#[verifier::when_used_as_spec(nr_pte_index_bits_spec)]
429pub fn nr_pte_index_bits<C: PagingConstsTrait>() -> (res: usize)
430    ensures
431        res == nr_pte_index_bits_spec::<C>(),
432{
433    proof {
434        lemma_nr_subpage_per_huge_bounded::<C>();
435    }
436    nr_subpage_per_huge::<C>().ilog2() as usize
437}
438
439pub proof fn lemma_nr_pte_index_bits_bounded<C: PagingConstsTrait>()
440    ensures
441        0 <= nr_pte_index_bits::<C>() <= C::BASE_PAGE_SIZE().ilog2(),
442{
443    lemma_nr_subpage_per_huge_bounded::<C>();
444    let nr = nr_subpage_per_huge::<C>();
445    assert(1 <= nr <= C::BASE_PAGE_SIZE());
446    let bits = nr.ilog2();
447    assert(0 <= bits) by {
448        lemma_usize_ilog2_ordered(1, nr);
449    }
450    assert(bits <= C::BASE_PAGE_SIZE().ilog2()) by {
451        lemma_usize_ilog2_ordered(nr, C::BASE_PAGE_SIZE());
452    }
453}
454
455/// Splits the address range into largest page table items.
456///
457/// Each of the returned items is a tuple of the physical address and the
458/// paging level. It is helpful when you want to map a physical address range
459/// into the provided virtual address.
460///
461/// For example, on x86-64, `C: PageTableConfig` may specify level 1 page as
462/// 4KiB, level 2 page as 2MiB, and level 3 page as 1GiB. Suppose that the
463/// supplied physical address range is from `0x3fdff000` to `0x80002000`,
464/// and the virtual address is also `0x3fdff000`, the following 5 items will
465/// be returned:
466///
467/// ```text
468/// 0x3fdff000                                                 0x80002000
469/// start                                                             end
470///   |----|----------------|--------------------------------|----|----|
471///    4KiB      2MiB                       1GiB              4KiB 4KiB
472/// ```
473///
474/// # Panics
475///
476/// Panics if:
477///  - any of `va`, `pa`, or `len` is not aligned to the base page size;
478///  - the range `va..(va + len)` is not valid for the page table.
479#[verifier::external_body]
480pub fn largest_pages<C: PageTableConfig>(
481    mut va: Vaddr,
482    mut pa: Paddr,
483    mut len: usize,
484) -> impl Iterator<Item = (Paddr, PagingLevel)> {
485    assert_eq!(va % C::BASE_PAGE_SIZE(), 0);
486    assert_eq!(pa % C::BASE_PAGE_SIZE(), 0);
487    assert_eq!(len % C::BASE_PAGE_SIZE(), 0);
488    assert!(is_valid_range::<C>(&(va..(va + len))));
489
490    core::iter::from_fn(
491        move ||
492            {
493                if len == 0 {
494                    return None;
495                }
496                let mut level = C::HIGHEST_TRANSLATION_LEVEL();
497                while page_size(level) > len || va % page_size(level) != 0 || pa % page_size(level)
498                    != 0 {
499                    level -= 1;
500                }
501
502                let item_start = pa;
503                va += page_size(level);
504                pa += page_size(level);
505                len -= page_size(level);
506
507                Some((item_start, level))
508            },
509    )
510}
511
512/// Gets the managed virtual addresses range for the page table.
513///
514/// It returns a [`RangeInclusive`] because the end address, if being
515/// [`Vaddr::MAX`], overflows [`Range<Vaddr>`].
516#[verifier::external_body]
517fn top_level_index_width<C: PageTableConfig>() -> usize {
518    C::ADDRESS_WIDTH() - pte_index_bit_offset::<C>(C::NR_LEVELS())
519}
520
521#[verifier::external_body]
522fn pt_va_range_start<C: PageTableConfig>() -> Vaddr {
523    C::TOP_LEVEL_INDEX_RANGE().start << pte_index_bit_offset::<C>(C::NR_LEVELS())
524}
525
526#[verifier::external_body]
527fn pt_va_range_end<C: PageTableConfig>() -> Vaddr {
528    C::TOP_LEVEL_INDEX_RANGE().end.unbounded_shl(
529        pte_index_bit_offset::<C>(C::NR_LEVELS()) as u32,
530    ).wrapping_sub(1)  // Inclusive end.
531
532}
533
534#[verifier::external_body]
535fn sign_bit_of_va<C: PageTableConfig>(va: Vaddr) -> bool {
536    (va >> (C::ADDRESS_WIDTH() - 1)) & 1 != 0
537}
538
539#[verifier::external_body]
540fn vaddr_range<C: PageTableConfig>() -> Range<Vaddr> {
541    /*    const {
542        assert!(C::TOP_LEVEL_INDEX_RANGE().start < C::TOP_LEVEL_INDEX_RANGE().end);
543        assert!(top_level_index_width::<C>() <= nr_pte_index_bits::<C>(),);
544        assert!(C::TOP_LEVEL_INDEX_RANGE().start < 1 << top_level_index_width::<C>());
545        assert!(C::TOP_LEVEL_INDEX_RANGE().end <= 1 << top_level_index_width::<C>());
546    };*/
547    let mut start = pt_va_range_start::<C>();
548    let mut end = pt_va_range_end::<C>();
549
550    /*    const {
551        assert!(
552            !C::VA_SIGN_EXT()
553                || sign_bit_of_va::<C>(pt_va_range_start::<C>())
554                    == sign_bit_of_va::<C>(pt_va_range_end::<C>()),
555            "The sign bit of both range endpoints must be the same if sign extension is enabled"
556        )
557    }*/
558
559    if C::VA_SIGN_EXT() && sign_bit_of_va::<C>(pt_va_range_start::<C>()) {
560        start |= !0 ^ ((1 << C::ADDRESS_WIDTH()) - 1);
561        end |= !0 ^ ((1 << C::ADDRESS_WIDTH()) - 1);
562    }
563    start..end + 1
564}
565
566/// Checks if the given range is covered by the valid range of the page table.
567#[verifier::external_body]
568fn is_valid_range<C: PageTableConfig>(r: &Range<Vaddr>) -> bool {
569    let va_range = vaddr_range::<C>();
570    (r.start == 0 && r.end == 0) || (va_range.start <= r.start && r.end - 1 <= va_range.end)
571}
572
573// Here are some const values that are determined by the paging constants.
574/// The index of a VA's PTE in a page table node at the given level.
575#[verifier::external_body]
576fn pte_index<C: PagingConstsTrait>(va: Vaddr, level: PagingLevel) -> (res: usize)
577    ensures
578        res == AbstractVaddr::from_vaddr(va).index[level - 1],
579{
580    (va >> pte_index_bit_offset::<C>(level)) & (nr_subpage_per_huge::<C>() - 1)
581}
582
583/// The bit offset of the entry offset part in a virtual address.
584///
585/// This function returns the bit offset of the least significant bit. Take
586/// x86-64 as an example, the `pte_index_bit_offset(2)` should return 21, which
587/// is 12 (the 4KiB in-page offset) plus 9 (index width in the level-1 table).
588#[verifier::external_body]
589fn pte_index_bit_offset<C: PagingConstsTrait>(level: PagingLevel) -> usize {
590    C::BASE_PAGE_SIZE().ilog2() as usize + nr_pte_index_bits::<C>() * (level as usize - 1)
591}
592
593/* TODO: stub out UserPtConfig
594
595impl PageTable<UserPtConfig> {
596    pub fn activate(&self) {
597        // SAFETY: The user mode page table is safe to activate since the kernel
598        // mappings are shared.
599        unsafe {
600            self.root.activate();
601        }
602    }
603}*/
604
605/* TODO: return here after kspace
606impl PageTable<KernelPtConfig> {
607    /// Create a new kernel page table.
608    pub(crate) fn new_kernel_page_table() -> Self {
609        let kpt = Self::empty();
610
611        // Make shared the page tables mapped by the root table in the kernel space.
612        {
613            let preempt_guard = disable_preempt();
614            let mut root_node = kpt.root.borrow().lock(&preempt_guard);
615
616            for i in KernelPtConfig::TOP_LEVEL_INDEX_RANGE {
617                let mut root_entry = root_node.entry(i);
618                let _ = root_entry.alloc_if_none(&preempt_guard).unwrap();
619            }
620        }
621
622        kpt
623    }
624
625    /// Create a new user page table.
626    ///
627    /// This should be the only way to create the user page table, that is to
628    /// duplicate the kernel page table with all the kernel mappings shared.
629    pub(in crate::mm) fn create_user_page_table(&'static self) -> PageTable<UserPtConfig> {
630        let new_root = PageTableNode::alloc(PagingConsts::NR_LEVELS);
631
632        let preempt_guard = disable_preempt();
633        let mut root_node = self.root.borrow().lock(&preempt_guard);
634        let mut new_node = new_root.borrow().lock(&preempt_guard);
635
636        const {
637            assert!(!KernelPtConfig::TOP_LEVEL_CAN_UNMAP);
638            assert!(
639                UserPtConfig::TOP_LEVEL_INDEX_RANGE.end
640                    <= KernelPtConfig::TOP_LEVEL_INDEX_RANGE.start
641            );
642        }
643
644        for i in KernelPtConfig::TOP_LEVEL_INDEX_RANGE {
645            let root_entry = root_node.entry(i);
646            let child = root_entry.to_ref();
647            let ChildRef::PageTable(pt) = child else {
648                panic!("The kernel page table doesn't contain shared nodes");
649            };
650
651            // We do not add additional reference count specifically for the
652            // shared kernel page tables. It requires user page tables to
653            // outlive the kernel page table, which is trivially true.
654            // See also `<PageTablePageMeta as AnyFrameMeta>::on_drop`.
655            let pt_addr = pt.start_paddr();
656            let pte = PageTableEntry::new_pt(pt_addr);
657            // SAFETY: The index is within the bounds and the PTE is at the
658            // correct paging level. However, neither it's a `UserPtConfig`
659            // child nor the node has the ownership of the child. It is
660            // still safe because `UserPtConfig::TOP_LEVEL_INDEX_RANGE`
661            // guarantees that the cursor won't access it.
662            unsafe { new_node.write_pte(i, pte) };
663        }
664        drop(new_node);
665
666        PageTable::<UserPtConfig> { root: new_root }
667    }
668
669    /// Protect the given virtual address range in the kernel page table.
670    ///
671    /// This method flushes the TLB entries when doing protection.
672    ///
673    /// # Safety
674    ///
675    /// The caller must ensure that the protection operation does not affect
676    /// the memory safety of the kernel.
677    pub unsafe fn protect_flush_tlb(
678        &self,
679        vaddr: &Range<Vaddr>,
680        mut op: impl FnMut(&mut PageProperty),
681    ) -> Result<(), PageTableError> {
682        let preempt_guard = disable_preempt();
683        let mut cursor = CursorMut::new(self, &preempt_guard, vaddr)?;
684        // SAFETY: The safety is upheld by the caller.
685        while let Some(range) =
686            unsafe { cursor.protect_next(vaddr.end - cursor.virt_addr(), &mut op) }
687        {
688            crate::arch::mm::tlb_flush_addr(range.start);
689        }
690        Ok(())
691    }
692}*/
693
694impl<C: PageTableConfig> PageTable<C> {
695    pub uninterp spec fn root_paddr_spec(&self) -> Paddr;
696
697    /// Create a new empty page table.
698    ///
699    /// Useful for the IOMMU page tables only.
700    #[verifier::external_body]
701    pub fn empty() -> Self {
702        unimplemented!()/*        PageTable {
703            root: PageTableNode::alloc(C::NR_LEVELS()),
704        }*/
705
706    }
707
708    #[verifier::external_body]
709    pub(in crate::mm) unsafe fn first_activate_unchecked(&self) {
710        unimplemented!()
711        // SAFETY: The safety is upheld by the caller.
712        //        unsafe { self.root.first_activate() };
713
714    }
715
716    /// The physical address of the root page table.
717    ///
718    /// Obtaining the physical address of the root page table is safe, however, using it or
719    /// providing it to the hardware will be unsafe since the page table node may be dropped,
720    /// resulting in UAF.
721    #[verifier::external_body]
722    #[verifier::when_used_as_spec(root_paddr_spec)]
723    pub fn root_paddr(&self) -> (r: Paddr)
724        returns
725            self.root_paddr_spec(),
726    {
727        unimplemented!()
728        //        self.root.start_paddr()
729
730    }
731
732    /// Query about the mapping of a single byte at the given virtual address.
733    ///
734    /// Note that this function may fail reflect an accurate result if there are
735    /// cursors concurrently accessing the same virtual address range, just like what
736    /// happens for the hardware MMU walk.
737    #[cfg(ktest)]
738    pub fn page_walk(&self, vaddr: Vaddr) -> Option<(Paddr, PageProperty)> {
739        // SAFETY: The root node is a valid page table node so the address is valid.
740        unsafe { page_walk::<C>(self.root_paddr(), vaddr) }
741    }
742
743    /// Create a new cursor exclusively accessing the virtual address range for mapping.
744    ///
745    /// If another cursor is already accessing the range, the new cursor may wait until the
746    /// previous cursor is dropped.
747    pub fn cursor_mut<'rcu, G: InAtomicMode>(
748        &'rcu self,
749        guard: &'rcu G,
750        va: &Range<Vaddr>,
751    ) -> Result<(CursorMut<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>), PageTableError> {
752        CursorMut::new(self, guard, va)
753    }
754
755    /// Create a new cursor exclusively accessing the virtual address range for querying.
756    ///
757    /// If another cursor is already accessing the range, the new cursor may wait until the
758    /// previous cursor is dropped. The modification to the mapping by the cursor may also
759    /// block or be overridden by the mapping of another cursor.
760    #[verus_spec(
761        with Tracked(owner): Tracked<&mut OwnerSubtree<C>>,
762            Tracked(guard_perm): Tracked<&vstd::simple_pptr::PointsTo<PageTableGuard<'rcu, C>>>
763    )]
764    pub fn cursor<'rcu, G: InAtomicMode>(&'rcu self, guard: &'rcu G, va: &Range<Vaddr>) -> Result<
765        (Cursor<'rcu, C, G>, Tracked<CursorOwner<'rcu, C>>),
766        PageTableError,
767    > {
768        #[verus_spec(with Tracked(owner), Tracked(guard_perm))]
769        Cursor::new(self, guard, va)
770    }/*
771    /// Create a new reference to the same page table.
772    /// The caller must ensure that the kernel page table is not copied.
773    /// This is only useful for IOMMU page tables. Think twice before using it in other cases.
774    pub unsafe fn shallow_copy(&self) -> Self {
775        PageTable {
776            root: self.root.clone(),
777        }
778    }
779    */
780
781}
782
783/// A software emulation of the MMU address translation process.
784///
785/// This method returns the physical address of the given virtual address and
786/// the page property if a valid mapping exists for the given virtual address.
787///
788/// # Safety
789///
790/// The caller must ensure that the `root_paddr` is a pointer to a valid root
791/// page table node.
792///
793/// # Notes on the page table use-after-free problem
794///
795/// Neither the hardware MMU nor the software page walk method acquires the page
796/// table locks while reading. They can enter a to-be-recycled page table node
797/// and read the page table entries after the node is recycled and reused.
798///
799/// For the hardware MMU page walk, we mitigate this problem by dropping the page
800/// table nodes only after the TLBs have been flushed on all the CPUs that
801/// activate the page table.
802///
803/// For the software page walk, we only need to disable preemption at the beginning
804/// since the page table nodes won't be recycled in the RCU critical section.
805#[cfg(ktest)]
806pub(super) unsafe fn page_walk<C: PageTableConfig>(root_paddr: Paddr, vaddr: Vaddr) -> Option<
807    (Paddr, PageProperty),
808> {
809    use super::paddr_to_vaddr;
810
811    let _rcu_guard = disable_preempt();
812
813    let mut pt_addr = paddr_to_vaddr(root_paddr);
814    #[verusfmt::skip]
815    for cur_level in (1..= C::NR_LEVELS()).rev() {
816        let offset = pte_index::<C>(vaddr, cur_level);
817        // SAFETY:
818        //  - The page table node is alive because (1) the root node is alive and
819        //    (2) all child nodes cannot be recycled because we're in the RCU critical section.
820        //  - The index is inside the bound, so the page table entry is valid.
821        //  - All page table entries are aligned and accessed with atomic operations only.
822        let cur_pte = unsafe { load_pte((pt_addr as *mut C::E).add(offset), Ordering::Acquire) };
823
824        if !cur_pte.is_present() {
825            return None;
826        }
827        if cur_pte.is_last(cur_level) {
828            debug_assert!(cur_level <= C::HIGHEST_TRANSLATION_LEVEL);
829            return Some(
830                (cur_pte.paddr() + (vaddr & (page_size::<C>(cur_level) - 1)), cur_pte.prop()),
831            );
832        }
833        pt_addr = paddr_to_vaddr(cur_pte.paddr());
834    }
835
836    unreachable!("All present PTEs at the level 1 must be last-level PTEs");
837}
838
839/// Loads a page table entry with an atomic instruction.
840///
841/// # Verification Design
842/// ## Preconditions
843/// - The pointer must be a valid pointer to the array that represents the page table node.
844/// - The array must be initialized at the target index.
845/// ## Postconditions
846/// - The value is loaded from the array at the given index.
847/// ## Safety
848/// - We require the caller to provide a permission token to ensure that this function is only called on a valid array
849/// and the pointer is in bounds.
850/// - Like an `AtomicUsize::load` in normal Rust, this function assumes that the value being loaded is an integer
851/// (and therefore can be safely cloned). We model the PTE as an abstract type, but in all actual implementations it is an
852/// integer. Importantly, it does not include any data that is unsafe to duplicate.
853#[verifier::external_body]
854#[verus_spec(
855    with Tracked(perm): Tracked<&vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
856    requires
857        perm.is_init(ptr.index as int),
858        perm.addr() == ptr.addr(),
859        0 <= ptr.index < NR_ENTRIES,
860    returns
861        perm.value()[ptr.index as int],
862)]
863pub fn load_pte<E: PageTableEntryTrait>(
864    ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
865    ordering: Ordering,
866) -> (pte: E) {
867    unimplemented!()
868}
869
870/// Stores a page table entry with an atomic instruction.
871///
872/// # Verification Design
873/// We axiomatize this function as a store operation in the array that represents the page table node.
874/// ## Preconditions
875/// - The pointer must be a valid pointer to the array that represents the page table node.
876/// - The array must be initialized so that the verifier knows that it remains initialized after the store.
877/// ## Postconditions
878/// - The new value is stored in the array at the given index.
879/// ## Safety
880/// - We require the caller to provide a permission token to ensure that this function is only called on a valid array
881/// and the pointer is in bounds.
882#[verifier::external_body]
883#[verus_spec(
884    with Tracked(perm): Tracked<&mut vstd_extra::array_ptr::PointsTo<E, NR_ENTRIES>>
885    requires
886        old(perm).addr() == ptr.addr(),
887        0 <= ptr.index < NR_ENTRIES,
888        old(perm).is_init_all(),
889    ensures
890        perm.value()[ptr.index as int] == new_val,
891        perm.value() == old(perm).value().update(ptr.index as int, new_val),
892        perm.addr() == old(perm).addr(),
893        perm.is_init_all(),
894)]
895pub fn store_pte<E: PageTableEntryTrait>(
896    ptr: vstd_extra::array_ptr::ArrayPtr<E, NR_ENTRIES>,
897    new_val: E,
898    ordering: Ordering,
899);
900
901} // verus!