From 5ba3f9a1a99fefe117a90120b144354a6c834aca Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Wed, 12 Jun 2024 08:55:59 +0000 Subject: [PATCH] Make global the boot page table --- framework/aster-frame/src/lib.rs | 6 +-- framework/aster-frame/src/mm/kspace.rs | 31 +++++++++++++--- framework/aster-frame/src/mm/mod.rs | 4 -- framework/aster-frame/src/mm/page/meta.rs | 20 +++++----- .../aster-frame/src/mm/page_table/boot_pt.rs | 37 +++---------------- 5 files changed, 44 insertions(+), 54 deletions(-) diff --git a/framework/aster-frame/src/lib.rs b/framework/aster-frame/src/lib.rs index 7fc827a9d..a36450ee8 100644 --- a/framework/aster-frame/src/lib.rs +++ b/framework/aster-frame/src/lib.rs @@ -76,15 +76,15 @@ pub fn init() { boot::init(); mm::page::allocator::init(); - let mut boot_pt = mm::get_boot_pt(); - mm::kspace::init_kernel_page_table(mm::init_page_meta(&mut boot_pt)); + mm::kspace::init_boot_page_table(); + mm::kspace::init_kernel_page_table(mm::init_page_meta()); mm::misc_init(); trap::init(); arch::after_all_init(); bus::init(); - mm::kspace::activate_kernel_page_table(boot_pt); + mm::kspace::activate_kernel_page_table(); invoke_ffi_init_funcs(); } diff --git a/framework/aster-frame/src/mm/kspace.rs b/framework/aster-frame/src/mm/kspace.rs index 5c69c05c3..c7c32af35 100644 --- a/framework/aster-frame/src/mm/kspace.rs +++ b/framework/aster-frame/src/mm/kspace.rs @@ -36,7 +36,7 @@ //! 39 bits or 57 bits, the memory space just adjust porportionally. use alloc::vec::Vec; -use core::ops::Range; +use core::{mem::ManuallyDrop, ops::Range}; use align_ext::AlignExt; use log::info; @@ -52,7 +52,10 @@ use super::{ page_table::{boot_pt::BootPageTable, KernelMode, PageTable}, MemoryRegionType, Paddr, PagingConstsTrait, Vaddr, PAGE_SIZE, }; -use crate::arch::mm::{PageTableEntry, PagingConsts}; +use crate::{ + arch::mm::{PageTableEntry, PagingConsts}, + sync::SpinLock, +}; /// The shortest supported address width is 39 bits. And the literal /// values are written for 48 bits address width. Adjust the values @@ -95,9 +98,25 @@ pub fn paddr_to_vaddr(pa: Paddr) -> usize { pa + LINEAR_MAPPING_BASE_VADDR } +/// The boot page table instance. +/// +/// It is used in the initialization phase before [`KERNEL_PAGE_TABLE`] is activated. +/// Since we want dropping the boot page table unsafe, it is wrapped in a [`ManuallyDrop`]. +pub static BOOT_PAGE_TABLE: SpinLock>> = SpinLock::new(None); + +/// The kernel page table instance. +/// +/// It manages the kernel mapping of all address spaces by sharing the kernel part. And it +/// is unlikely to be activated. pub static KERNEL_PAGE_TABLE: Once> = Once::new(); +/// Initializes the boot page table. +pub(crate) fn init_boot_page_table() { + let boot_pt = BootPageTable::from_current_pt(); + *BOOT_PAGE_TABLE.lock() = Some(ManuallyDrop::new(boot_pt)); +} + /// Initializes the kernel page table. /// /// This function should be called after: @@ -201,7 +220,7 @@ pub fn init_kernel_page_table(meta_pages: Vec>) { KERNEL_PAGE_TABLE.call_once(|| kpt); } -pub fn activate_kernel_page_table(boot_pt: BootPageTable) { +pub fn activate_kernel_page_table() { let kpt = KERNEL_PAGE_TABLE .get() .expect("The kernel page table is not initialized yet"); @@ -210,7 +229,9 @@ pub fn activate_kernel_page_table(boot_pt: BootPageTable page_table::boot_pt::BootPageTable { - unsafe { page_table::boot_pt::BootPageTable::from_current_pt() } -} diff --git a/framework/aster-frame/src/mm/page/meta.rs b/framework/aster-frame/src/mm/page/meta.rs index 822ab30a6..36986dbe9 100644 --- a/framework/aster-frame/src/mm/page/meta.rs +++ b/framework/aster-frame/src/mm/page/meta.rs @@ -53,12 +53,9 @@ use super::Page; use crate::{ arch::mm::{PageTableEntry, PagingConsts}, mm::{ - paddr_to_vaddr, - page::allocator::FRAME_ALLOCATOR, - page_size, - page_table::{boot_pt::BootPageTable, PageTableEntryTrait}, - CachePolicy, Paddr, PageFlags, PageProperty, PagingConstsTrait, PagingLevel, - PrivilegedPageFlags, PAGE_SIZE, + kspace::BOOT_PAGE_TABLE, paddr_to_vaddr, page::allocator::FRAME_ALLOCATOR, page_size, + page_table::PageTableEntryTrait, CachePolicy, Paddr, PageFlags, PageProperty, + PagingConstsTrait, PagingLevel, PrivilegedPageFlags, PAGE_SIZE, }, }; @@ -191,7 +188,7 @@ impl PageMeta for KernelMeta { /// Initializes the metadata of all physical pages. /// /// The function returns a list of `Page`s containing the metadata. -pub(crate) fn init(boot_pt: &mut BootPageTable) -> Vec> { +pub(crate) fn init() -> Vec> { let max_paddr = { let regions = crate::boot::memory_regions(); regions.iter().map(|r| r.base() + r.len()).max().unwrap() @@ -207,8 +204,11 @@ pub(crate) fn init(boot_pt: &mut BootPageTable) -> Vec> { let num_pages = max_paddr / page_size::(1); let num_meta_pages = (num_pages * size_of::()).div_ceil(PAGE_SIZE); let meta_pages = alloc_meta_pages(num_meta_pages); - // Map the metadata pages. + let mut boot_pt_lock = BOOT_PAGE_TABLE.lock(); + let boot_pt = boot_pt_lock + .as_mut() + .expect("boot page table not initialized"); for (i, frame_paddr) in meta_pages.iter().enumerate() { let vaddr = mapping::page_to_meta::(0) + i * PAGE_SIZE; let prop = PageProperty { @@ -216,9 +216,9 @@ pub(crate) fn init(boot_pt: &mut BootPageTable) -> Vec> { cache: CachePolicy::Writeback, priv_flags: PrivilegedPageFlags::GLOBAL, }; - boot_pt.map_base_page(vaddr, frame_paddr / PAGE_SIZE, prop); + // SAFETY: we are doing the metadata mappings for the kernel. + unsafe { boot_pt.map_base_page(vaddr, frame_paddr / PAGE_SIZE, prop) }; } - // Now the metadata pages are mapped, we can initialize the metadata. meta_pages .into_iter() diff --git a/framework/aster-frame/src/mm/page_table/boot_pt.rs b/framework/aster-frame/src/mm/page_table/boot_pt.rs index 0927cb908..f59ac5764 100644 --- a/framework/aster-frame/src/mm/page_table/boot_pt.rs +++ b/framework/aster-frame/src/mm/page_table/boot_pt.rs @@ -34,10 +34,7 @@ pub struct BootPageTable< impl BootPageTable { /// Creates a new boot page table from the current page table root physical address. - /// - /// The caller must ensure that the current page table may be set up by the firmware, - /// loader or the setup code. - pub unsafe fn from_current_pt() -> Self { + pub fn from_current_pt() -> Self { let root_paddr = crate::arch::mm::current_page_table_paddr(); Self { root_pt: root_paddr / C::BASE_PAGE_SIZE, @@ -48,7 +45,7 @@ impl BootPageTable { /// Maps a base page to a frame. /// This function will panic if the page is already mapped. - pub fn map_base_page(&mut self, from: Vaddr, to: FrameNumber, prop: PageProperty) { + pub unsafe fn map_base_page(&mut self, from: Vaddr, to: FrameNumber, prop: PageProperty) { let mut pt = self.root_pt; let mut level = C::NR_LEVELS; // Walk to the last level of the page table. @@ -85,37 +82,13 @@ impl BootPageTable { unsafe { core::ptr::write_bytes(vaddr, 0, PAGE_SIZE) }; frame } - - /// Retires this boot-stage page table. - /// - /// Do not drop a boot-stage page table. Instead, retire it. - /// - /// # Safety - /// - /// This method can only be called when this boot-stage page table is no longer in use, - /// e.g., after the permanent kernel page table has been activated. - pub unsafe fn retire(mut self) { - // Manually free all heap and frame memory allocated. - let frames = core::mem::take(&mut self.frames); - for frame in frames { - FRAME_ALLOCATOR.get().unwrap().lock().dealloc(frame, 1); - } - // We do not want or need to trigger drop. - core::mem::forget(self); - // FIXME: an empty `Vec` is leaked on the heap here since the drop is not called - // and we have no ways to free it. - // The best solution to recycle the boot-phase page table is to initialize all - // page table page metadata of the boot page table by page walk after the metadata - // pages are mapped. Therefore the boot page table can be recycled or dropped by - // the routines in the [`super::node`] module. There's even without a need of - // `first_activate` concept if the boot page table can be managed by page table - // pages. - } } impl Drop for BootPageTable { fn drop(&mut self) { - panic!("the boot page table is dropped rather than retired."); + for frame in &self.frames { + FRAME_ALLOCATOR.get().unwrap().lock().dealloc(*frame, 1); + } } }