Make global the boot page table
This commit is contained in:
parent
5c7c1bb39b
commit
5ba3f9a1a9
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue