Skip to main content

ostd/mm/kspace/
mod.rs

1// SPDX-License-Identifier: MPL-2.0
2//! Kernel memory space management.
3//!
4//! The kernel memory space is currently managed as follows, if the
5//! address width is 48 bits (with 47 bits kernel space).
6//!
7//! TODO: the cap of linear mapping (the start of vm alloc) are raised
8//! to workaround for high IO in TDX. We need actual vm alloc API to have
9//! a proper fix.
10//!
11//! ```text
12//! +-+ <- the highest used address (0xffff_ffff_ffff_0000)
13//! | |         For the kernel code, 1 GiB.
14//! +-+ <- 0xffff_ffff_8000_0000
15//! | |
16//! | |         Unused hole.
17//! +-+ <- 0xffff_e100_0000_0000
18//! | |         For frame metadata, 1 TiB.
19//! +-+ <- 0xffff_e000_0000_0000
20//! | |         For [`KVirtArea`], 32 TiB.
21//! +-+ <- the middle of the higher half (0xffff_c000_0000_0000)
22//! | |
23//! | |
24//! | |
25//! | |         For linear mappings, 64 TiB.
26//! | |         Mapped physical addresses are untracked.
27//! | |
28//! | |
29//! | |
30//! +-+ <- the base of high canonical address (0xffff_8000_0000_0000)
31//! ```
32//!
33//! If the address width is (according to [`crate::arch::mm::PagingConsts`])
34//! 39 bits or 57 bits, the memory space just adjust proportionally.
35use core::ops::Range;
36use vstd::atomic::PermissionU64;
37use vstd::prelude::*;
38use vstd::simple_pptr::PointsTo;
39
40//use log::info;
41use 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::mm::NR_LEVELS;
58use crate::specs::mm::frame::meta_owners::MetaPerm;
59use crate::specs::mm::frame::meta_owners::MetaSlotStorage;
60use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
61use crate::{
62    boot::memory_region::MemoryRegionType,
63    mm::{PagingLevel, largest_pages},
64    specs::arch::{PageTableEntry, PagingConsts},
65    //task::disable_preempt,
66};
67
68use vstd_extra::ownership::*;
69
70verus! {
71
72/// The shortest supported address width is 39 bits. And the literal
73/// values are written for 48 bits address width. Adjust the values
74/// by arithmetic left shift.
75pub const ADDR_WIDTH_SHIFT: isize = 48 - 48;
76
77/// Start of the kernel address space.
78/// This is the _lowest_ address of the x86-64's _high_ canonical addresses.
79#[cfg(not(target_arch = "loongarch64"))]
80pub const KERNEL_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
81
82#[cfg(target_arch = "loongarch64")]
83pub const KERNEL_BASE_VADDR: Vaddr = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
84
85/// End of the kernel address space (non inclusive).
86pub const KERNEL_END_VADDR: Vaddr = 0xffff_ffff_ffff_0000 << ADDR_WIDTH_SHIFT;
87
88/*
89/// The kernel code is linear mapped to this address.
90///
91/// FIXME: This offset should be randomly chosen by the loader or the
92/// boot compatibility layer. But we disabled it because OSTD
93/// doesn't support relocatable kernel yet.
94pub fn kernel_loaded_offset() -> usize {
95    KERNEL_CODE_BASE_VADDR
96}*/
97
98#[cfg(target_arch = "x86_64")]
99const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_8000_0000 << ADDR_WIDTH_SHIFT;
100
101#[cfg(target_arch = "riscv64")]
102const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_0000_0000 << ADDR_WIDTH_SHIFT;
103
104#[cfg(target_arch = "loongarch64")]
105const KERNEL_CODE_BASE_VADDR: usize = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
106
107pub const FRAME_METADATA_CAP_VADDR: Vaddr = 0xffff_e100_0000_0000 << ADDR_WIDTH_SHIFT;
108
109pub const FRAME_METADATA_BASE_VADDR: Vaddr = 0xffff_e000_0000_0000 << ADDR_WIDTH_SHIFT;
110
111pub const VMALLOC_BASE_VADDR: Vaddr = 0xffff_c000_0000_0000 << ADDR_WIDTH_SHIFT;
112
113pub const VMALLOC_VADDR_RANGE: Range<Vaddr> = VMALLOC_BASE_VADDR..FRAME_METADATA_BASE_VADDR;
114
115/// The base address of the linear mapping of all physical
116/// memory in the kernel address space.
117pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
118
119pub const LINEAR_MAPPING_VADDR_RANGE: Range<Vaddr> = LINEAR_MAPPING_BASE_VADDR..VMALLOC_BASE_VADDR;
120
121/*
122#[cfg(not(target_arch = "loongarch64"))]
123pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0xffff_8000_0000_0000 << ADDR_WIDTH_SHIFT;
124#[cfg(target_arch = "loongarch64")]
125pub const LINEAR_MAPPING_BASE_VADDR: Vaddr = 0x9000_0000_0000_0000 << ADDR_WIDTH_SHIFT;
126pub const LINEAR_MAPPING_VADDR_RANGE: Range<Vaddr> = LINEAR_MAPPING_BASE_VADDR..VMALLOC_BASE_VADDR;
127*/
128
129/// Convert physical address to virtual address using offset, only available inside `ostd`
130pub open spec fn paddr_to_vaddr_spec(pa: Paddr) -> usize {
131    (pa + LINEAR_MAPPING_BASE_VADDR) as usize
132}
133
134#[verifier::when_used_as_spec(paddr_to_vaddr_spec)]
135pub fn paddr_to_vaddr(pa: Paddr) -> usize
136    requires
137        pa + LINEAR_MAPPING_BASE_VADDR < usize::MAX,
138    returns
139        paddr_to_vaddr_spec(pa),
140{
141    //debug_assert!(pa < VMALLOC_BASE_VADDR - LINEAR_MAPPING_BASE_VADDR);
142    pa + LINEAR_MAPPING_BASE_VADDR
143}
144
145/// The kernel page table instance.
146///
147/// It manages the kernel mapping of all address spaces by sharing the kernel part. And it
148/// is unlikely to be activated.
149#[allow(private_interfaces)]
150pub exec static KERNEL_PAGE_TABLE: OnceImpl<PageTable<KernelPtConfig>, TrivialPred> = OnceImpl::new(
151    Ghost(TrivialPred),
152);
153
154#[derive(Clone, Debug)]
155pub(crate) struct KernelPtConfig {}
156
157// We use the first available PTE bit to mark the frame as tracked.
158// SAFETY: `item_into_raw` and `item_from_raw` are implemented correctly,
159unsafe impl PageTableConfig for KernelPtConfig {
160    open spec fn TOP_LEVEL_INDEX_RANGE_spec() -> Range<usize> {
161        256..512
162    }
163
164    open spec fn LEADING_BITS_spec() -> usize {
165        0xffff
166    }
167
168    fn TOP_LEVEL_INDEX_RANGE() -> (r: Range<usize>)
169        ensures
170            r == Self::TOP_LEVEL_INDEX_RANGE_spec(),
171    {
172        256..512
173    }
174
175    open spec fn TOP_LEVEL_CAN_UNMAP_spec() -> bool {
176        false
177    }
178
179    fn TOP_LEVEL_CAN_UNMAP() -> (b: bool)
180        ensures
181            b == Self::TOP_LEVEL_CAN_UNMAP_spec(),
182    {
183        false
184    }
185
186    // The kvirt allocator (the only source of kernel-PT cursor ranges) caps
187    // `range.end` at FRAME_METADATA_BASE_VADDR — see `kvirt_alloc_range_bounds`.
188    open spec fn LOCKED_END_BOUND_spec() -> int {
189        FRAME_METADATA_BASE_VADDR as int
190    }
191
192    type E = PageTableEntry;
193
194    type C = PagingConsts;
195
196    type Item = MappedItem;
197
198    uninterp spec fn item_into_raw_spec(item: Self::Item) -> (Paddr, PagingLevel, PageProperty);
199
200    //    #[verifier::when_used_as_spec(item_into_raw_spec)]
201    #[verifier::external_body]
202    fn item_into_raw(item: Self::Item) -> (res: (Paddr, PagingLevel, PageProperty))
203        ensures
204            1 <= res.1 <= crate::specs::arch::mm::NR_LEVELS,
205            res == Self::item_into_raw_spec(item),
206    {
207        match item {
208            MappedItem::Tracked(frame, mut prop) => {
209                debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
210                prop.flags = prop.flags | PageFlags::AVAIL1();
211                let level = frame.map_level();
212                let paddr = frame.into_raw();
213                (paddr, level, prop)
214            },
215            MappedItem::Untracked(pa, level, mut prop) => {
216                debug_assert!(!prop.flags.contains(PageFlags::AVAIL1()));
217                prop.flags = prop.flags - PageFlags::AVAIL1();
218                (pa, level, prop)
219            },
220        }
221    }
222
223    uninterp spec fn item_from_raw_spec(
224        paddr: Paddr,
225        level: PagingLevel,
226        prop: PageProperty,
227    ) -> Self::Item;
228
229    //#[verifier::when_used_as_spec(item_from_raw_spec)]
230    #[verifier::external_body]
231    unsafe fn item_from_raw(paddr: Paddr, level: PagingLevel, prop: PageProperty) -> (res:
232        Self::Item)
233        ensures
234            res == Self::item_from_raw_spec(paddr, level, prop),
235    {
236        if prop.flags.contains(PageFlags::AVAIL1()) {
237            debug_assert_eq!(level, 1);
238            // SAFETY: The caller ensures safety.
239            let frame = unsafe { Frame::<MetaSlotStorage>::from_raw(paddr) };
240            MappedItem::Tracked(frame, prop)
241        } else {
242            MappedItem::Untracked(paddr, level, prop)
243        }
244    }
245
246    axiom fn axiom_nr_subpage_per_huge_eq_nr_entries();
247
248    axiom fn axiom_pte_size_eq_size_of();
249
250    axiom fn axiom_pte_walk_fills_page();
251
252    axiom fn axiom_top_level_index_range_within_nr_entries();
253
254    axiom fn axiom_pte_align_divides_size();
255
256    axiom fn item_roundtrip(item: Self::Item, paddr: Paddr, level: PagingLevel, prop: PageProperty);
257
258    open spec fn tracked(item: Self::Item) -> bool {
259        // Tracked items hold a reference; clone bumps rc. Untracked items
260        // (MMIO frames) are not ref-counted; clone is a no-op.
261        item is Tracked
262    }
263
264    open spec fn item_well_formed(item: Self::Item) -> bool {
265        match item {
266            MappedItem::Tracked(frame, _) => frame.inv(),
267            MappedItem::Untracked(_, _, _) => true,
268        }
269    }
270
271    proof fn item_from_raw_well_formed(pa: Paddr, level: PagingLevel, prop: PageProperty) {
272        broadcast use crate::mm::frame::meta::mapping::group_page_meta;
273
274        let item = Self::item_from_raw_spec(pa, level, prop);
275        if prop.flags.contains(crate::mm::page_prop::PageFlags::AVAIL1()) {
276            // Tracked branch: derive `frame.inv()` from
277            //   - `item_from_raw_spec_tracked_ptr`: frame.ptr.addr() == frame_to_meta(pa).
278            //   - `lemma_frame_to_meta_soundness` (broadcast): frame_to_meta(pa) is
279            //     META_SLOT_SIZE-aligned and within FRAME_METADATA_RANGE.
280            Self::item_from_raw_spec_tracked_ptr(pa, level, prop);
281            // Now item is `MappedItem::Tracked(frame, _)` with the address fact.
282            match item {
283                MappedItem::Tracked(frame, _) => {
284                    assert(frame.ptr.addr() == crate::mm::frame::meta::mapping::frame_to_meta(pa));
285                    // frame.inv() unfolds to (alignment + range), both from the lemma.
286                    assert(frame.inv());
287                },
288                MappedItem::Untracked(_, _, _) => {
289                    // Excluded by item_from_raw_spec_tracked_ptr.
290                    assert(false);
291                },
292            }
293        } else {
294            // Untracked branch: item_well_formed is `true`.
295            Self::item_from_raw_spec_untracked_variant(pa, level, prop);
296        }
297    }
298
299    proof fn clone_ensures_concrete(
300        item: Self::Item,
301        pa: Paddr,
302        old_regions: MetaRegionOwners,
303        new_regions: MetaRegionOwners,
304        res: Self::Item,
305    ) {
306        // `MappedItem::clone_ensures` case-analyzes:
307        //   - Tracked: `frame.clone_ensures(old, new, res_frame)` — gives per-field facts at
308        //     `frame_to_index(meta_to_frame(frame.ptr.addr()))`. Bridge to `frame_to_index(pa)`.
309        //   - Untracked: `old == new`. Then trait's `rc + 1` ensures becomes contradictory.
310        //     This case is ASSUMED unreachable (clone_item only runs on Tracked items in
311        //     the verified call chain).
312        // Force the trait method's open-spec body to unfold by asserting the UFCS form.
313        assert(<MappedItem as RCClone>::clone_ensures(item, old_regions, new_regions, res));
314        match (item, res) {
315            (MappedItem::Tracked(frame, prop_actual), MappedItem::Tracked(res_frame, _)) => {
316                use crate::mm::frame::meta::mapping::{frame_to_index, meta_to_frame};
317                Self::item_into_raw_spec_tracked_pa(frame, prop_actual);
318                let frame_idx = frame_to_index(meta_to_frame(frame.ptr.addr()));
319                assert(pa == meta_to_frame(frame.ptr.addr()));
320                assert(frame_to_index(pa) == frame_idx);
321                assert(frame.clone_ensures(old_regions, new_regions, res_frame));
322                // Canonical: the cloned frame minted one obligation at its slot.
323                assert(new_regions.frame_obligations =~= old_regions.frame_obligations.insert(
324                    frame_idx,
325                ));
326            },
327            (MappedItem::Untracked(_, _, _), _) => {
328                // clone_ensures for Untracked is `old == new`; the trait's
329                // `!tracked ==> slot unchanged` ensures follows directly, and
330                // the per-frame ledger is preserved (net-zero clone).
331                assert(old_regions == new_regions);
332            },
333            _ => {
334                // res == item by precondition; if item is Tracked, res is Tracked too.
335                // The mismatched-tag arm is unreachable.
336                assert(res == item);
337            },
338        }
339    }
340
341    proof fn clone_requires_concrete(
342        item: Self::Item,
343        pa: Paddr,
344        level: PagingLevel,
345        prop: PageProperty,
346        regions: MetaRegionOwners,
347    ) {
348        // `MappedItem::clone_requires` case-analyzes:
349        //   - Tracked: `frame.clone_requires(regions)` — needs `frame.inv()` and the
350        //     slot facts at `frame_to_index(meta_to_frame(frame.ptr.addr()))`.
351        //   - Untracked: `regions.inv()`. Trivially satisfied from precondition.
352        // Discharge `frame.inv()` via the trait-level structural well-formedness method.
353        Self::item_from_raw_well_formed(pa, level, prop);
354        match item {
355            MappedItem::Tracked(frame, prop_actual) => {
356                use crate::mm::frame::meta::mapping::{frame_to_index, meta_to_frame};
357                Self::item_into_raw_spec_tracked_pa(frame, prop_actual);
358                Self::item_roundtrip(item, pa, level, prop);
359                assert(meta_to_frame(frame.ptr.addr()) == pa);
360                assert(frame_to_index(meta_to_frame(frame.ptr.addr())) == frame_to_index(pa));
361                // `Self::item_well_formed(item)` unfolds to `frame.inv()` for the
362                // Tracked variant.
363                assert(frame.inv());
364            },
365            MappedItem::Untracked(_, _, _) => {
366                // clone_requires for Untracked is just `regions.inv()` which we have.
367            },
368        }
369    }
370}
371
372impl KernelPtConfig {
373    /// The spec agrees with the exec, which ensures 1 <= level <= NR_LEVELS.
374    pub axiom fn item_into_raw_spec_level_bounds(item: MappedItem)
375        ensures
376            1 <= KernelPtConfig::item_into_raw_spec(item).1 <= crate::specs::arch::mm::NR_LEVELS,
377    ;
378
379    /// Tracked frames use 4K pages (level 1). Used to prove alignment in map_frames.
380    pub axiom fn item_into_raw_spec_tracked_level(item: MappedItem)
381        requires
382            matches!(item, MappedItem::Tracked(_, _)),
383        ensures
384            KernelPtConfig::item_into_raw_spec(item).1 == 1,
385    ;
386
387    /// For untracked items, `item_into_raw_spec` preserves PA, level, and prop.
388    /// This is correct when the AVAIL1 bit is not set in `prop`, which is assumed
389    /// for untracked MMIO frames (enforced by the debug_assert in the exec).
390    pub axiom fn item_into_raw_spec_untracked(pa: Paddr, level: PagingLevel, prop: PageProperty)
391        ensures
392            KernelPtConfig::item_into_raw_spec(MappedItem::Untracked(pa, level, prop)).0 == pa,
393            KernelPtConfig::item_into_raw_spec(MappedItem::Untracked(pa, level, prop)).1 == level,
394            KernelPtConfig::item_into_raw_spec(MappedItem::Untracked(pa, level, prop)).2 == prop,
395    ;
396
397    /// For tracked items, the physical address from item_into_raw_spec equals
398    /// the frame's metadata-derived physical address.
399    pub axiom fn item_into_raw_spec_tracked_pa(frame: DynFrame, prop: PageProperty)
400        ensures
401            KernelPtConfig::item_into_raw_spec(MappedItem::Tracked(frame, prop)).0
402                == crate::mm::frame::meta::mapping::meta_to_frame(frame.ptr.addr()),
403    ;
404
405    /// For tracked items, item_into_raw_spec returns the same `prop` that was passed in.
406    pub axiom fn item_into_raw_spec_tracked_prop(frame: DynFrame, prop: PageProperty)
407        ensures
408            KernelPtConfig::item_into_raw_spec(MappedItem::Tracked(frame, prop)).2 == prop,
409    ;
410
411    /// Structural shape of `item_from_raw_spec` for the Tracked branch: the reconstructed
412    /// frame's pointer is `frame_to_meta(pa)`. This mirrors the exec body of `item_from_raw`,
413    /// which calls `Frame::from_raw(pa)` whose ensures gives `r.ptr.addr() == frame_to_meta(pa)`.
414    /// Once we have this address shape, `Frame::inv()` follows from `lemma_frame_to_meta_soundness`.
415    pub axiom fn item_from_raw_spec_tracked_ptr(pa: Paddr, level: PagingLevel, prop: PageProperty)
416        requires
417            crate::mm::frame::meta::has_safe_slot(pa),
418            prop.flags.contains(crate::mm::page_prop::PageFlags::AVAIL1()),
419        ensures
420            match KernelPtConfig::item_from_raw_spec(pa, level, prop) {
421                MappedItem::Tracked(frame, _) => frame.ptr.addr()
422                    == crate::mm::frame::meta::mapping::frame_to_meta(pa),
423                MappedItem::Untracked(_, _, _) => false,
424            },
425    ;
426
427    /// For untracked items, `item_from_raw_spec` returns the Untracked variant.
428    /// Mirrors the exec body's branch on `prop.flags.contains(AVAIL1)`.
429    pub axiom fn item_from_raw_spec_untracked_variant(
430        pa: Paddr,
431        level: PagingLevel,
432        prop: PageProperty,
433    )
434        requires
435            !prop.flags.contains(crate::mm::page_prop::PageFlags::AVAIL1()),
436        ensures
437            matches!(KernelPtConfig::item_from_raw_spec(pa, level, prop),
438                MappedItem::Untracked(_, _, _)),
439    ;
440
441    /// For KernelPtConfig (x86_64): HIGHEST_TRANSLATION_LEVEL = 2 < NR_LEVELS = 4.
442    pub axiom fn axiom_kernel_htl_lt_nr_levels()
443        ensures
444            (KernelPtConfig::HIGHEST_TRANSLATION_LEVEL() as int) < NR_LEVELS as int,
445    ;
446}
447
448/*
449#[derive(Clone, Debug, PartialEq, Eq)]
450pub(crate) enum MappedItem {
451    Tracked(Frame<dyn AnyFrameMeta>, PageProperty),
452    Untracked(Paddr, PagingLevel, PageProperty),
453}
454*/
455
456pub enum MappedItem {
457    Tracked(DynFrame, PageProperty),
458    Untracked(Paddr, PagingLevel, PageProperty),
459}
460
461impl RCClone for MappedItem {
462    open spec fn clone_requires(self, perm: MetaRegionOwners) -> bool {
463        match self {
464            MappedItem::Tracked(frame, _) => frame.clone_requires(perm),
465            MappedItem::Untracked(_, _, _) => perm.inv(),
466        }
467    }
468
469    open spec fn clone_ensures(
470        self,
471        old_perm: MetaRegionOwners,
472        new_perm: MetaRegionOwners,
473        res: Self,
474    ) -> bool {
475        match (self, res) {
476            (
477                MappedItem::Tracked(frame, _),
478                MappedItem::Tracked(res_frame, _),
479            ) => frame.clone_ensures(old_perm, new_perm, res_frame),
480            (MappedItem::Untracked(_, _, _), _) => old_perm == new_perm,
481            _ => true,
482        }
483    }
484
485    #[verifier::external_body]
486    fn clone(&self, Tracked(perm): Tracked<&mut MetaRegionOwners>) -> (res: Self) {
487        unimplemented!();
488    }
489}
490
491} // verus!
492// /// Initializes the kernel page table.
493// ///
494// /// This function should be called after:
495// ///  - the page allocator and the heap allocator are initialized;
496// ///  - the memory regions are initialized.
497// ///
498// /// This function should be called before:
499// ///  - any initializer that modifies the kernel page table.
500// pub fn init_kernel_page_table(meta_pages: Segment<MetaPageMeta>) {
501//     info!("Initializing the kernel page table");
502//     // Start to initialize the kernel page table.
503//     let kpt = PageTable::<KernelPtConfig>::new_kernel_page_table();
504//     let preempt_guard = disable_preempt();
505//     // In LoongArch64, we don't need to do linear mappings for the kernel because of DMW0.
506//     #[cfg(not(target_arch = "loongarch64"))]
507//     // Do linear mappings for the kernel.
508//     {
509//         let max_paddr = crate::mm::frame::max_paddr();
510//         let from = LINEAR_MAPPING_BASE_VADDR..LINEAR_MAPPING_BASE_VADDR + max_paddr;
511//         let prop = PageProperty {
512//             flags: PageFlags::RW,
513//             cache: CachePolicy::Writeback,
514//             priv_flags: PrivilegedPageFlags::GLOBAL,
515//         };
516//         let mut cursor = kpt.cursor_mut(&preempt_guard, &from).unwrap();
517//         for (pa, level) in largest_pages::<KernelPtConfig>(from.start, 0, max_paddr) {
518//             // SAFETY: we are doing the linear mapping for the kernel.
519//             unsafe { cursor.map(MappedItem::Untracked(pa, level, prop)) }
520//                 .expect("Kernel linear address space is mapped twice");
521//         }
522//     }
523//     // Map the metadata pages.
524//     {
525//         let start_va = mapping::frame_to_meta::<PagingConsts>(0);
526//         let from = start_va..start_va + meta_pages.size();
527//         let prop = PageProperty {
528//             flags: PageFlags::RW,
529//             cache: CachePolicy::Writeback,
530//             priv_flags: PrivilegedPageFlags::GLOBAL,
531//         };
532//         let mut cursor = kpt.cursor_mut(&preempt_guard, &from).unwrap();
533//         // We use untracked mapping so that we can benefit from huge pages.
534//         // We won't unmap them anyway, so there's no leaking problem yet.
535//         // TODO: support tracked huge page mapping.
536//         let pa_range = meta_pages.into_raw();
537//         for (pa, level) in
538//             largest_pages::<KernelPtConfig>(from.start, pa_range.start, pa_range.len())
539//         {
540//             // SAFETY: We are doing the metadata mappings for the kernel.
541//             unsafe { cursor.map(MappedItem::Untracked(pa, level, prop)) }
542//                 .expect("Frame metadata address space is mapped twice");
543//         }
544//     }
545//     // In LoongArch64, we don't need to do linear mappings for the kernel code because of DMW0.
546//     #[cfg(not(target_arch = "loongarch64"))]
547//     // Map for the kernel code itself.
548//     // TODO: set separated permissions for each segments in the kernel.
549//     {
550//         let regions = &crate::boot::EARLY_INFO.get().unwrap().memory_regions;
551//         let region = regions
552//             .iter()
553//             .find(|r| r.typ() == MemoryRegionType::Kernel)
554//             .unwrap();
555//         let offset = kernel_loaded_offset();
556//         let from = region.base() + offset..region.end() + offset;
557//         let prop = PageProperty {
558//             flags: PageFlags::RWX,
559//             cache: CachePolicy::Writeback,
560//             priv_flags: PrivilegedPageFlags::GLOBAL,
561//         };
562//         let mut cursor = kpt.cursor_mut(&preempt_guard, &from).unwrap();
563//         for (pa, level) in largest_pages::<KernelPtConfig>(from.start, region.base(), from.len()) {
564//             // SAFETY: we are doing the kernel code mapping.
565//             unsafe { cursor.map(MappedItem::Untracked(pa, level, prop)) }
566//                 .expect("Kernel code mapped twice");
567//         }
568//     }
569//     KERNEL_PAGE_TABLE.call_once(|| kpt);
570// }
571// /// Activates the kernel page table.
572// ///
573// /// # Safety
574// ///
575// /// This function should only be called once per CPU.
576// pub unsafe fn activate_kernel_page_table() {
577//     let kpt = KERNEL_PAGE_TABLE
578//         .get()
579//         .expect("The kernel page table is not initialized yet");
580//     // SAFETY: the kernel page table is initialized properly.
581//     unsafe {
582//         kpt.first_activate_unchecked();
583//         crate::arch::mm::tlb_flush_all_including_global();
584//     }
585//     // SAFETY: the boot page table is OK to be dismissed now since
586//     // the kernel page table is activated just now.
587//     unsafe {
588//         crate::mm::page_table::boot_pt::dismiss();
589//     }
590// }