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