Make global the boot page table

This commit is contained in:
Zhang Junyang 2024-06-12 08:55:59 +00:00 committed by Tate, Hongliang Tian
parent 5c7c1bb39b
commit 5ba3f9a1a9
5 changed files with 44 additions and 54 deletions

View File

@ -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();
}

View File

@ -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<Option<ManuallyDrop<BootPageTable>>> = 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<PageTable<KernelMode, PageTableEntry, PagingConsts>> =
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<Range<Paddr>>) {
KERNEL_PAGE_TABLE.call_once(|| kpt);
}
pub fn activate_kernel_page_table(boot_pt: BootPageTable<PageTableEntry, PagingConsts>) {
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<PageTableEntry, PagingC
kpt.first_activate_unchecked();
crate::arch::mm::tlb_flush_all_including_global();
}
// SAFETY: the boot page table is OK to be retired now since
// SAFETY: the boot page table is OK to be dropped now since
// the kernel page table is activated.
unsafe { boot_pt.retire() };
let mut boot_pt = BOOT_PAGE_TABLE.lock().take().unwrap();
unsafe { ManuallyDrop::drop(&mut boot_pt) };
}

View File

@ -131,7 +131,3 @@ pub(crate) fn misc_init() {
}
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
}
pub(crate) fn get_boot_pt() -> page_table::boot_pt::BootPageTable {
unsafe { page_table::boot_pt::BootPageTable::from_current_pt() }
}

View File

@ -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<Range<Paddr>> {
pub(crate) fn init() -> Vec<Range<Paddr>> {
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<Range<Paddr>> {
let num_pages = max_paddr / page_size::<PagingConsts>(1);
let num_meta_pages = (num_pages * size_of::<MetaSlot>()).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::<PagingConsts>(0) + i * PAGE_SIZE;
let prop = PageProperty {
@ -216,9 +216,9 @@ pub(crate) fn init(boot_pt: &mut BootPageTable) -> Vec<Range<Paddr>> {
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()

View File

@ -34,10 +34,7 @@ pub struct BootPageTable<
impl<E: PageTableEntryTrait, C: PagingConstsTrait> BootPageTable<E, C> {
/// 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<E: PageTableEntryTrait, C: PagingConstsTrait> BootPageTable<E, C> {
/// 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<E: PageTableEntryTrait, C: PagingConstsTrait> BootPageTable<E, C> {
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<E: PageTableEntryTrait, C: PagingConstsTrait> Drop for BootPageTable<E, C> {
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);
}
}
}