From 92bc8cbbf79a03bc0cfe7b9616e4252a6dc21792 Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Wed, 8 Jan 2025 20:27:45 +0800 Subject: [PATCH] Make CPU-local and early ACPI initialization heap-less --- Cargo.lock | 4 +- ostd/Cargo.toml | 2 +- ostd/src/arch/riscv/mod.rs | 12 +-- ostd/src/arch/x86/boot/smp.rs | 24 +++-- ostd/src/arch/x86/device/cmos.rs | 8 +- ostd/src/arch/x86/kernel/acpi/dmar.rs | 4 +- ostd/src/arch/x86/kernel/acpi/mod.rs | 37 +++++-- ostd/src/arch/x86/kernel/apic/ioapic.rs | 11 +- ostd/src/arch/x86/mod.rs | 22 ++-- ostd/src/arch/x86/timer/hpet.rs | 8 +- ostd/src/cpu/local/cpu_local.rs | 17 +-- ostd/src/cpu/local/mod.rs | 137 ++++++++++++++---------- ostd/src/lib.rs | 26 +++-- ostd/src/mm/frame/meta.rs | 15 ++- ostd/src/mm/mod.rs | 3 +- ostd/src/task/mod.rs | 1 - ostd/src/task/preempt/cpu_local.rs | 14 --- 17 files changed, 188 insertions(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 129633dc4..2649f50d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "acpi" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e42f25ac5fa51f4188d14baf8f387a97dcd8639644b2f3df948bf5f6dd7d6fa" +checksum = "94476c7ef97af4c4d998b3f422c1b01d5211aad57c80ed200baf148d1f1efab6" dependencies = [ "bit_field", "bitflags 2.6.0", diff --git a/ostd/Cargo.toml b/ostd/Cargo.toml index ce839eb0b..f72ce35cb 100644 --- a/ostd/Cargo.toml +++ b/ostd/Cargo.toml @@ -42,7 +42,7 @@ xarray = { git = "https://github.com/asterinas/xarray", version = "0.1.0" } [target.x86_64-unknown-none.dependencies] x86_64 = "0.14.13" x86 = "0.52.0" -acpi = "5.1.0" +acpi = "=5.2.0" # This upstream often bump minor versions with API changes multiboot2 = "0.23.0" iced-x86 = { version = "1.21.0", default-features = false, features = [ "no_std", diff --git a/ostd/src/arch/riscv/mod.rs b/ostd/src/arch/riscv/mod.rs index 89030a1a9..8574cdb5e 100644 --- a/ostd/src/arch/riscv/mod.rs +++ b/ostd/src/arch/riscv/mod.rs @@ -22,23 +22,13 @@ pub(crate) fn init_cvm_guest() { // Unimplemented, no-op } -pub(crate) fn init_on_bsp() { +pub(crate) unsafe fn late_init_on_bsp() { // SAFETY: this function is only called once on BSP. unsafe { trap::init(true); } irq::init(); - // SAFETY: they are only called once on BSP and ACPI has been initialized. - unsafe { - crate::cpu::init_num_cpus(); - crate::cpu::set_this_cpu_id(0); - } - - // SAFETY: no CPU local objects have been accessed by this far. And - // we are on the BSP. - unsafe { crate::cpu::local::init_on_bsp() }; - crate::boot::smp::boot_all_aps(); timer::init(); diff --git a/ostd/src/arch/x86/boot/smp.rs b/ostd/src/arch/x86/boot/smp.rs index bd980ce56..bb8bfc197 100644 --- a/ostd/src/arch/x86/boot/smp.rs +++ b/ostd/src/arch/x86/boot/smp.rs @@ -27,11 +27,9 @@ //! This sequence does not need to be strictly followed, and there may be //! different considerations in different systems. -use acpi::platform::PlatformInfo; - use crate::{ arch::x86::kernel::{ - acpi::ACPI_TABLES, + acpi::get_acpi_tables, apic::{ self, ApicId, DeliveryMode, DeliveryStatus, DestinationMode, DestinationShorthand, Icr, Level, TriggerMode, @@ -44,14 +42,20 @@ use crate::{ /// /// This function needs to be called after the OS initializes the ACPI table. pub(crate) fn get_num_processors() -> Option { - if !ACPI_TABLES.is_completed() { - return None; - } - let processor_info = PlatformInfo::new(&*ACPI_TABLES.get().unwrap().lock()) + let acpi_tables = get_acpi_tables()?; + let mut local_apic_counts = 0; + acpi_tables + .find_table::() .unwrap() - .processor_info - .unwrap(); - Some(processor_info.application_processors.len() as u32 + 1) + .get() + .entries() + .for_each(|entry| { + if let acpi::madt::MadtEntry::LocalApic(_) = entry { + local_apic_counts += 1; + } + }); + + Some(local_apic_counts) } /// Brings up all application processors. diff --git a/ostd/src/arch/x86/device/cmos.rs b/ostd/src/arch/x86/device/cmos.rs index 6aab22e57..b7b1316d2 100644 --- a/ostd/src/arch/x86/device/cmos.rs +++ b/ostd/src/arch/x86/device/cmos.rs @@ -13,7 +13,7 @@ use acpi::fadt::Fadt; use x86_64::instructions::port::{ReadOnlyAccess, WriteOnlyAccess}; use super::io_port::IoPort; -use crate::arch::x86::kernel::acpi::ACPI_TABLES; +use crate::arch::x86::kernel::acpi::get_acpi_tables; /// CMOS address I/O port pub static CMOS_ADDRESS: IoPort = unsafe { IoPort::new(0x70) }; @@ -23,10 +23,8 @@ pub static CMOS_DATA: IoPort = unsafe { IoPort::new(0x71) }; /// Gets the century register location. This function is used in RTC(Real Time Clock) module initialization. pub fn century_register() -> Option { - if !ACPI_TABLES.is_completed() { - return None; - } - match ACPI_TABLES.get().unwrap().lock().find_table::() { + let acpi_tables = get_acpi_tables()?; + match acpi_tables.find_table::() { Ok(a) => Some(a.century), Err(er) => None, } diff --git a/ostd/src/arch/x86/kernel/acpi/dmar.rs b/ostd/src/arch/x86/kernel/acpi/dmar.rs index e8944e5bf..3269b41dd 100644 --- a/ostd/src/arch/x86/kernel/acpi/dmar.rs +++ b/ostd/src/arch/x86/kernel/acpi/dmar.rs @@ -74,9 +74,9 @@ unsafe impl AcpiTable for DmarHeader { impl Dmar { /// Creates a instance from ACPI table. pub fn new() -> Option { - let acpi_table_lock = super::ACPI_TABLES.get()?.lock(); + let acpi_table = super::get_acpi_tables()?; - let dmar_mapping = acpi_table_lock.find_table::().ok()?; + let dmar_mapping = acpi_table.find_table::().ok()?; let header = *dmar_mapping; // SAFETY: `find_table` returns a region of memory that belongs to the ACPI table. This diff --git a/ostd/src/arch/x86/kernel/acpi/mod.rs b/ostd/src/arch/x86/kernel/acpi/mod.rs index ac0b93c0b..9abcee87e 100644 --- a/ostd/src/arch/x86/kernel/acpi/mod.rs +++ b/ostd/src/arch/x86/kernel/acpi/mod.rs @@ -5,19 +5,15 @@ pub mod remapping; use core::ptr::NonNull; -use acpi::{rsdp::Rsdp, AcpiHandler, AcpiTables}; +use acpi::{platform::PlatformInfo, rsdp::Rsdp, AcpiHandler, AcpiTables}; use log::{info, warn}; use spin::Once; use crate::{ boot::{self, BootloaderAcpiArg}, mm::paddr_to_vaddr, - sync::SpinLock, }; -/// RSDP information, key is the signature, value is the virtual address of the signature -pub static ACPI_TABLES: Once>> = Once::new(); - #[derive(Debug, Clone)] pub struct AcpiMemoryHandler {} @@ -42,7 +38,7 @@ impl AcpiHandler for AcpiMemoryHandler { fn unmap_physical_region(_region: &acpi::PhysicalMapping) {} } -pub fn init() { +pub(crate) fn get_acpi_tables() -> Option> { let acpi_tables = match boot::EARLY_INFO.get().unwrap().acpi_arg { BootloaderAcpiArg::Rsdp(addr) => unsafe { AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap() @@ -62,16 +58,39 @@ pub fn init() { }, Err(_) => { warn!("ACPI info not found!"); - return; + return None; } } } }; + Some(acpi_tables) +} + +static PLATFORM_INFO: Once> = Once::new(); + +/// Initializes the platform information by parsing ACPI tables in to the heap. +/// +/// Must be called after the heap is initialized. +pub(crate) fn init() { + let Some(acpi_tables) = get_acpi_tables() else { + return; + }; + for header in acpi_tables.headers() { info!("ACPI found signature:{:?}", header.signature); } - ACPI_TABLES.call_once(|| SpinLock::new(acpi_tables)); - info!("acpi init complete"); + let platform_info = PlatformInfo::new(&acpi_tables).unwrap(); + PLATFORM_INFO.call_once(|| platform_info); + + info!("ACPI initialization complete"); +} + +/// Gets the platform information. +/// +/// Must be called after [`init()`]. Otherwise, there may not be any platform +/// information even if the system has ACPI tables. +pub(crate) fn get_platform_info() -> Option<&'static PlatformInfo<'static, alloc::alloc::Global>> { + PLATFORM_INFO.get() } diff --git a/ostd/src/arch/x86/kernel/apic/ioapic.rs b/ostd/src/arch/x86/kernel/apic/ioapic.rs index 71be5099d..5a9656c5e 100644 --- a/ostd/src/arch/x86/kernel/apic/ioapic.rs +++ b/ostd/src/arch/x86/kernel/apic/ioapic.rs @@ -5,7 +5,6 @@ use alloc::{vec, vec::Vec}; use core::ptr::NonNull; -use acpi::PlatformInfo; use bit_field::BitField; use cfg_if::cfg_if; use log::info; @@ -16,7 +15,7 @@ use volatile::{ }; use crate::{ - arch::{iommu::has_interrupt_remapping, x86::kernel::acpi::ACPI_TABLES}, + arch::{iommu::has_interrupt_remapping, x86::kernel::acpi::get_platform_info}, mm::paddr_to_vaddr, sync::SpinLock, trap::IrqLine, @@ -180,7 +179,7 @@ impl IoApicAccess { pub static IO_APIC: Once>> = Once::new(); pub fn init() { - if !ACPI_TABLES.is_completed() { + let Some(platform_info) = get_platform_info() else { IO_APIC.call_once(|| { // FIXME: Is it possible to have an address that is not the default 0xFEC0_0000? // Need to find a way to determine if it is a valid address or not. @@ -211,10 +210,8 @@ pub fn init() { vec![SpinLock::new(IoApic::new(io_apic, 0))] }); return; - } - let table = ACPI_TABLES.get().unwrap().lock(); - let platform_info = PlatformInfo::new(&*table).unwrap(); - match platform_info.interrupt_model { + }; + match &platform_info.interrupt_model { acpi::InterruptModel::Unknown => panic!("not found APIC in ACPI Table"), acpi::InterruptModel::Apic(apic) => { let mut vec = Vec::new(); diff --git a/ostd/src/arch/x86/mod.rs b/ostd/src/arch/x86/mod.rs index 3a2367b22..d81dc9947 100644 --- a/ostd/src/arch/x86/mod.rs +++ b/ostd/src/arch/x86/mod.rs @@ -63,19 +63,21 @@ pub(crate) fn init_cvm_guest() { static CPU_FEATURES: Once = Once::new(); -pub(crate) fn init_on_bsp() { +/// Architecture-specific initialization on the bootstrapping processor. +/// +/// It should be called when the heap and frame allocators are available. +/// +/// # Safety +/// +/// This function must be called only once on the bootstrapping processor. +pub(crate) unsafe fn late_init_on_bsp() { // SAFETY: this function is only called once on BSP. unsafe { crate::arch::trap::init(true); } irq::init(); - kernel::acpi::init(); - // SAFETY: they are only called once on BSP and ACPI has been initialized. - unsafe { - crate::cpu::init_num_cpus(); - crate::cpu::set_this_cpu_id(0); - } + kernel::acpi::init(); match kernel::apic::init() { Ok(_) => { @@ -88,12 +90,6 @@ pub(crate) fn init_on_bsp() { } serial::callback_init(); - // SAFETY: no CPU local objects have been accessed by this far. And - // we are on the BSP. - unsafe { crate::cpu::local::init_on_bsp() }; - - crate::sync::init(); - crate::boot::smp::boot_all_aps(); timer::init(); diff --git a/ostd/src/arch/x86/timer/hpet.rs b/ostd/src/arch/x86/timer/hpet.rs index 4a53e467f..d5155ddd9 100644 --- a/ostd/src/arch/x86/timer/hpet.rs +++ b/ostd/src/arch/x86/timer/hpet.rs @@ -11,7 +11,7 @@ use volatile::{ }; use crate::{ - arch::x86::kernel::{acpi::ACPI_TABLES, apic::ioapic}, + arch::x86::kernel::{acpi::get_acpi_tables, apic::ioapic}, mm::paddr_to_vaddr, trap::IrqLine, }; @@ -135,11 +135,9 @@ impl Hpet { /// HPET init, need to init IOAPIC before init this function #[expect(dead_code)] pub fn init() -> Result<(), AcpiError> { - let hpet_info = { - let lock = ACPI_TABLES.get().unwrap().lock(); - HpetInfo::new(&*lock)? - }; + let tables = get_acpi_tables().unwrap(); + let hpet_info = HpetInfo::new(&tables)?; assert_ne!(hpet_info.base_address, 0, "HPET address should not be zero"); let base = NonNull::new(paddr_to_vaddr(hpet_info.base_address) as *mut u8).unwrap(); diff --git a/ostd/src/cpu/local/cpu_local.rs b/ostd/src/cpu/local/cpu_local.rs index 035181ee0..62e1b30d2 100644 --- a/ostd/src/cpu/local/cpu_local.rs +++ b/ostd/src/cpu/local/cpu_local.rs @@ -141,24 +141,15 @@ impl CpuLocal { /// Panics if the CPU ID is out of range. pub fn get_on_cpu(&'static self, cpu_id: CpuId) -> &'static T { super::has_init::assert_true(); - - let cpu_id = cpu_id.as_usize(); - // If on the BSP, just use the statically linked storage. - if cpu_id == 0 { + if cpu_id.as_usize() == 0 { return &self.0; } // SAFETY: Here we use `Once::get_unchecked` to make getting the CPU- - // local base faster. The storages must be initialized here so it is - // safe to do so. - let base = unsafe { - super::CPU_LOCAL_STORAGES - .get_unchecked() - .get(cpu_id - 1) - .unwrap() - .start_paddr() - }; + // local base faster. The storages must be initialized here (since this + // is not the BSP) so it is safe to do so. + let base = unsafe { super::CPU_LOCAL_STORAGES.get_unchecked().get(cpu_id) }; let base = crate::mm::paddr_to_vaddr(base); let offset = self.get_offset(); diff --git a/ostd/src/cpu/local/mod.rs b/ostd/src/cpu/local/mod.rs index bd122cef0..1794989d9 100644 --- a/ostd/src/cpu/local/mod.rs +++ b/ostd/src/cpu/local/mod.rs @@ -34,16 +34,17 @@ mod cpu_local; pub(crate) mod single_instr; -use alloc::vec::Vec; +use core::alloc::Layout; use align_ext::AlignExt; pub use cell::CpuLocalCell; pub use cpu_local::{CpuLocal, CpuLocalDerefGuard}; use spin::Once; +use super::CpuId; use crate::{ arch, - mm::{frame::Segment, kspace::KernelMeta, paddr_to_vaddr, FrameAllocOptions, PAGE_SIZE}, + mm::{frame::allocator, paddr_to_vaddr, Paddr, PAGE_SIZE}, }; // These symbols are provided by the linker script. @@ -52,30 +53,81 @@ extern "C" { fn __cpu_local_end(); } -/// Sets the base address of the CPU-local storage for the bootstrap processor. -/// -/// It should be called early to let [`crate::task::disable_preempt`] work, -/// which needs to update a CPU-local preemption info. Otherwise it may -/// panic when calling [`crate::task::disable_preempt`]. It is needed since -/// heap allocations need to disable preemption, which would happen in the -/// very early stage of the kernel. -/// -/// # Safety -/// -/// It should be called only once and only on the BSP. -pub(crate) unsafe fn early_init_bsp_local_base() { - let start_base_va = __cpu_local_start as usize as u64; +/// The BSP initializes the CPU-local areas for APs. +static CPU_LOCAL_STORAGES: Once = Once::new(); - // SAFETY: The base to be set is the start of the `.cpu_local` section, - // where accessing the CPU-local objects have defined behaviors. - unsafe { - arch::cpu::local::set_base(start_base_va); +struct CpuLocalStoragePointers(&'static mut [Paddr]); + +impl CpuLocalStoragePointers { + /// Allocates frames for storing CPU-local data for each AP. + /// + /// # Safety + /// + /// The caller must ensure that the `num_cpus` matches the number of all + /// CPUs that will access CPU local storage. + /// + /// The BSP's CPU-local storage should not be touched before calling + /// this method, since the CPU-local storage for APs is copied from the + /// BSP's CPU-local storage. + unsafe fn allocate(num_cpus: usize) -> Self { + let num_aps = num_cpus - 1; // BSP does not need allocated storage. + assert!(num_aps > 0, "No APs to allocate CPU-local storage"); + + // Allocate a region to store the pointers to the CPU-local storage segments. + let size = (core::mem::size_of::() * num_aps).align_up(PAGE_SIZE); + let addr = + allocator::early_alloc(Layout::from_size_align(size, PAGE_SIZE).unwrap()).unwrap(); + let ptr = paddr_to_vaddr(addr) as *mut Paddr; + // SAFETY: The memory is allocated and the pointer is valid. + unsafe { + core::ptr::write_bytes(ptr as *mut u8, 0, size); + } + // SAFETY: The memory would not be deallocated. And it is valid. + let res = Self(unsafe { core::slice::from_raw_parts_mut(ptr, num_aps) }); + + // Allocate the CPU-local storage segments for APs. + let bsp_base_va = __cpu_local_start as usize; + let bsp_end_va = __cpu_local_end as usize; + for id in 0..num_aps { + let ap_pages = { + let nbytes = (bsp_end_va - bsp_base_va).align_up(PAGE_SIZE); + allocator::early_alloc(Layout::from_size_align(nbytes, PAGE_SIZE).unwrap()).unwrap() + }; + let ap_pages_ptr = paddr_to_vaddr(ap_pages) as *mut u8; + + // SAFETY: The BSP has not initialized the CPU-local area, so the objects in + // in the `.cpu_local` section can be bitwise bulk copied to the AP's local + // storage. The destination memory is allocated so it is valid to write to. + unsafe { + core::ptr::copy_nonoverlapping( + bsp_base_va as *const u8, + ap_pages_ptr, + bsp_end_va - bsp_base_va, + ); + } + + res.0[id] = ap_pages; + } + + res + } + + fn get(&self, cpu_id: CpuId) -> Paddr { + let offset = cpu_id + .as_usize() + .checked_sub(1) + .expect("The BSP does not have allocated CPU-local storage"); + + let paddr = self.0[offset]; + assert!( + paddr != 0, + "The CPU-local storage for CPU {} is not allocated", + cpu_id.as_usize() + ); + paddr } } -/// The BSP initializes the CPU-local areas for APs. -static CPU_LOCAL_STORAGES: Once>> = Once::new(); - /// Initializes the CPU local data for the bootstrap processor (BSP). /// /// # Safety @@ -86,39 +138,17 @@ static CPU_LOCAL_STORAGES: Once>> = Once::new(); /// this function being called, otherwise copying non-constant values /// will result in pretty bad undefined behavior. pub unsafe fn init_on_bsp() { - let bsp_base_va = __cpu_local_start as usize; - let bsp_end_va = __cpu_local_end as usize; - let num_cpus = super::num_cpus(); - let mut cpu_local_storages = Vec::with_capacity(num_cpus - 1); - for _ in 1..num_cpus { - let ap_pages = { - let nbytes = (bsp_end_va - bsp_base_va).align_up(PAGE_SIZE); - FrameAllocOptions::new() - .zeroed(false) - .alloc_segment_with(nbytes / PAGE_SIZE, |_| KernelMeta) - .unwrap() - }; - let ap_pages_ptr = paddr_to_vaddr(ap_pages.start_paddr()) as *mut u8; + if num_cpus > 1 { + // SAFETY: The number of CPUs is correct. And other conditions are + // the caller's safety conditions. + let cpu_local_storages = unsafe { CpuLocalStoragePointers::allocate(num_cpus) }; - // SAFETY: The BSP has not initialized the CPU-local area, so the objects in - // in the `.cpu_local` section can be bitwise bulk copied to the AP's local - // storage. The destination memory is allocated so it is valid to write to. - unsafe { - core::ptr::copy_nonoverlapping( - bsp_base_va as *const u8, - ap_pages_ptr, - bsp_end_va - bsp_base_va, - ); - } - - cpu_local_storages.push(ap_pages); + CPU_LOCAL_STORAGES.call_once(|| cpu_local_storages); } - CPU_LOCAL_STORAGES.call_once(|| cpu_local_storages); - - arch::cpu::local::set_base(bsp_base_va as u64); + arch::cpu::local::set_base(__cpu_local_start as usize as u64); has_init::set_true(); } @@ -132,17 +162,14 @@ pub unsafe fn init_on_ap(cpu_id: u32) { let ap_pages = CPU_LOCAL_STORAGES .get() .unwrap() - .get(cpu_id as usize - 1) - .unwrap(); + .get(CpuId::try_from(cpu_id as usize).unwrap()); - let ap_pages_ptr = paddr_to_vaddr(ap_pages.start_paddr()) as *mut u32; + let ap_pages_ptr = paddr_to_vaddr(ap_pages) as *mut u32; // SAFETY: the memory will be dedicated to the AP. And we are on the AP. unsafe { arch::cpu::local::set_base(ap_pages_ptr as u64); } - - crate::task::reset_preempt_info(); } mod has_init { diff --git a/ostd/src/lib.rs b/ostd/src/lib.rs index 0b3b93c1f..79e5588d5 100644 --- a/ostd/src/lib.rs +++ b/ostd/src/lib.rs @@ -47,7 +47,7 @@ mod util; use core::sync::atomic::{AtomicBool, Ordering}; -pub use ostd_macros::{main, panic_handler}; +pub use ostd_macros::{global_frame_allocator, main, panic_handler}; pub use ostd_pod::Pod; pub use self::{error::Error, prelude::Result}; @@ -74,19 +74,33 @@ unsafe fn init() { logger::init(); - // SAFETY: This function is called only once and only on the BSP. - unsafe { cpu::local::early_init_bsp_local_base() }; + // SAFETY: They are only called once on BSP and ACPI has been initialized. + // No CPU local objects have been accessed by this far. + unsafe { + cpu::init_num_cpus(); + cpu::local::init_on_bsp(); + cpu::set_this_cpu_id(0); + } + + // SAFETY: We are on the BSP and APs are not yet started. + let meta_pages = unsafe { mm::frame::meta::init() }; + // The frame allocator should be initialized immediately after the metadata + // is initialized. Otherwise the boot page table can't allocate frames. + // SAFETY: This function is called only once. + unsafe { mm::frame::allocator::init() }; + + mm::kspace::init_kernel_page_table(meta_pages); // SAFETY: This function is called only once and only on the BSP. unsafe { mm::heap_allocator::init() }; + crate::sync::init(); + boot::init_after_heap(); - mm::frame::allocator::init(); - mm::kspace::init_kernel_page_table(mm::init_page_meta()); mm::dma::init(); - arch::init_on_bsp(); + unsafe { arch::late_init_on_bsp() }; smp::init(); diff --git a/ostd/src/mm/frame/meta.rs b/ostd/src/mm/frame/meta.rs index ed6274c62..442dd8cf9 100644 --- a/ostd/src/mm/frame/meta.rs +++ b/ostd/src/mm/frame/meta.rs @@ -442,7 +442,12 @@ impl_frame_meta_for!(MetaPageMeta); /// Initializes the metadata of all physical frames. /// /// The function returns a list of `Frame`s containing the metadata. -pub(crate) fn init() -> Segment { +/// +/// # Safety +/// +/// This function should be called only once and only on the BSP, +/// before any APs are started. +pub(crate) unsafe fn init() -> Segment { let max_paddr = { let regions = &crate::boot::EARLY_INFO.get().unwrap().memory_regions; regions.iter().map(|r| r.base() + r.len()).max().unwrap() @@ -518,6 +523,14 @@ fn alloc_meta_frames(tot_nr_frames: usize) -> (usize, Paddr) { (nr_meta_pages, start_paddr) } +/// Returns whether the global frame allocator is initialized. +pub(in crate::mm) fn is_initialized() -> bool { + // `init` sets it somewhere in the middle. But due to the safety + // requirement of the `init` function, we can assume that there + // is no race condition. + super::MAX_PADDR.load(Ordering::Relaxed) != 0 +} + /// Adds a temporary linear mapping for the metadata frames. /// /// We only assume boot page table to contain 4G linear mapping. Thus if the diff --git a/ostd/src/mm/mod.rs b/ostd/src/mm/mod.rs index 1fa0de3b2..31d832f9c 100644 --- a/ostd/src/mm/mod.rs +++ b/ostd/src/mm/mod.rs @@ -39,8 +39,7 @@ pub use self::{ vm_space::VmSpace, }; pub(crate) use self::{ - frame::meta::init as init_page_meta, kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, - page_table::PageTable, + kspace::paddr_to_vaddr, page_prop::PrivilegedPageFlags, page_table::PageTable, }; use crate::arch::mm::PagingConsts; diff --git a/ostd/src/task/mod.rs b/ostd/src/task/mod.rs index c5ecb9ca7..320bd9392 100644 --- a/ostd/src/task/mod.rs +++ b/ostd/src/task/mod.rs @@ -18,7 +18,6 @@ use core::{ }; use kernel_stack::KernelStack; -pub(crate) use preempt::cpu_local::reset_preempt_info; use processor::current_task; use utils::ForceSync; diff --git a/ostd/src/task/preempt/cpu_local.rs b/ostd/src/task/preempt/cpu_local.rs index e9928d660..ff730d547 100644 --- a/ostd/src/task/preempt/cpu_local.rs +++ b/ostd/src/task/preempt/cpu_local.rs @@ -57,19 +57,5 @@ cpu_local_cell! { static PREEMPT_INFO: u32 = NEED_PREEMPT_MASK; } -/// Resets the preempt info to the initial state. -/// -/// # Safety -/// -/// This function is only useful for the initialization of application -/// processors' CPU-local storage. Because that the BSP should access the CPU- -/// local storage (`PREEMPT_INFO`) (when doing heap allocation) before we can -/// initialize the CPU-local storage for APs, the value of the AP's -/// `PREEMPT_INFO` would be that of the BSP's. Therefore, we need to reset the -/// `PREEMPT_INFO` to the initial state on APs' initialization. -pub(crate) unsafe fn reset_preempt_info() { - PREEMPT_INFO.store(NEED_PREEMPT_MASK); -} - const NEED_PREEMPT_MASK: u32 = 1 << 31; const GUARD_COUNT_MASK: u32 = (1 << 31) - 1;