From 69cbfc72f5b482023b8a4e000ffc8bc945096334 Mon Sep 17 00:00:00 2001 From: Zhang Junyang Date: Tue, 25 Jul 2023 12:22:03 +0800 Subject: [PATCH] Refactor boot and add placeholder kcmdline struct --- .../src/arch/x86/boot/{multiboot2 => }/boot.S | 0 .../jinux-frame/src/arch/x86/boot/mod.rs | 80 +------------------ .../boot/{multiboot2/mod.rs => multiboot2.rs} | 54 +++++++------ .../src/arch/x86/kernel/acpi/mod.rs | 5 +- framework/jinux-frame/src/arch/x86/mod.rs | 1 - framework/jinux-frame/src/boot/kcmdline.rs | 23 ++++++ .../src/{arch/x86 => }/boot/memory_region.rs | 0 framework/jinux-frame/src/boot/mod.rs | 78 ++++++++++++++++++ framework/jinux-frame/src/lib.rs | 4 +- .../jinux-frame/src/vm/frame_allocator.rs | 2 +- framework/jinux-frame/src/vm/mod.rs | 5 +- services/comps/framebuffer/src/lib.rs | 2 +- services/libs/jinux-std/src/lib.rs | 4 +- 13 files changed, 145 insertions(+), 113 deletions(-) rename framework/jinux-frame/src/arch/x86/boot/{multiboot2 => }/boot.S (100%) rename framework/jinux-frame/src/arch/x86/boot/{multiboot2/mod.rs => multiboot2.rs} (82%) create mode 100644 framework/jinux-frame/src/boot/kcmdline.rs rename framework/jinux-frame/src/{arch/x86 => }/boot/memory_region.rs (100%) create mode 100644 framework/jinux-frame/src/boot/mod.rs diff --git a/framework/jinux-frame/src/arch/x86/boot/multiboot2/boot.S b/framework/jinux-frame/src/arch/x86/boot/boot.S similarity index 100% rename from framework/jinux-frame/src/arch/x86/boot/multiboot2/boot.S rename to framework/jinux-frame/src/arch/x86/boot/boot.S diff --git a/framework/jinux-frame/src/arch/x86/boot/mod.rs b/framework/jinux-frame/src/arch/x86/boot/mod.rs index 0ce0e2af8..d61101167 100644 --- a/framework/jinux-frame/src/arch/x86/boot/mod.rs +++ b/framework/jinux-frame/src/arch/x86/boot/mod.rs @@ -4,84 +4,6 @@ //! We currently support Multiboot2. The support for Linux Boot Protocol is //! on its way. //! -//! In this module, we use println! to print information on screen rather -//! than logging since the logger is not initialized here. -//! pub mod multiboot2; -use self::multiboot2::init_global_boot_statics; - -pub mod memory_region; -use self::memory_region::MemoryRegion; - -use alloc::{string::String, vec::Vec}; -use spin::Once; - -/// The boot crate can choose either providing the raw RSDP physical address or -/// providing the RSDT/XSDT physical address after parsing RSDP. -/// This is because bootloaders differ in such behaviors. -#[derive(Copy, Clone, Debug)] -pub enum BootloaderAcpiArg { - /// Physical address of the RSDP. - Rsdp(usize), - /// Address of RSDT provided in RSDP v1. - Rsdt(usize), - /// Address of XSDT provided in RSDP v2+. - Xsdt(usize), -} - -/// The framebuffer arguments. -#[derive(Copy, Clone, Debug)] -pub struct BootloaderFramebufferArg { - pub address: usize, - pub width: usize, - pub height: usize, - /// Bits per pixel of the buffer. - pub bpp: usize, -} - -/// After initializing the boot module, the get_* functions could be called. -/// The initialization must be done after the heap is set and before physical -/// mappings are cancelled. -pub fn init() { - init_global_boot_statics(); -} - -// The public get_* APIs. - -static BOOTLOADER_NAME: Once = Once::new(); -/// Get the name and the version of the bootloader. -pub fn get_bootloader_name() -> String { - BOOTLOADER_NAME.get().unwrap().clone() -} - -static KERNEL_COMMANDLINE: Once = Once::new(); -/// Get the raw unparsed kernel commandline string. -pub fn get_kernel_commandline() -> String { - KERNEL_COMMANDLINE.get().unwrap().clone() -} - -static INITRAMFS: Once<&'static [u8]> = Once::new(); -/// The slice of the bootloader-loaded init ram disk. -pub fn get_initramfs() -> &'static [u8] { - INITRAMFS.get().unwrap() -} - -static ACPI_RSDP: Once = Once::new(); -/// The ACPI RDSP/XSDT address. -pub fn get_acpi_rsdp() -> BootloaderAcpiArg { - ACPI_RSDP.get().unwrap().clone() -} - -static FRAMEBUFFER_INFO: Once = Once::new(); -/// Framebuffer information. -pub fn get_framebuffer_info() -> BootloaderFramebufferArg { - FRAMEBUFFER_INFO.get().unwrap().clone() -} - -static MEMORY_REGIONS: Once> = Once::new(); -/// Get memory regions. -/// The returned usable memory regions are guarenteed to not overlap with other unusable ones. -pub fn get_memory_regions() -> Vec { - MEMORY_REGIONS.get().unwrap().clone() -} +pub use self::multiboot2::init_boot_args; diff --git a/framework/jinux-frame/src/arch/x86/boot/multiboot2/mod.rs b/framework/jinux-frame/src/arch/x86/boot/multiboot2.rs similarity index 82% rename from framework/jinux-frame/src/arch/x86/boot/multiboot2/mod.rs rename to framework/jinux-frame/src/arch/x86/boot/multiboot2.rs index d8f3239c0..36d15d8e3 100644 --- a/framework/jinux-frame/src/arch/x86/boot/multiboot2/mod.rs +++ b/framework/jinux-frame/src/arch/x86/boot/multiboot2.rs @@ -1,10 +1,9 @@ -use alloc::{string::ToString, vec::Vec}; +use alloc::{string::{ToString, String}, vec::Vec}; use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType}; -use super::{ +use crate::boot::{ memory_region::{MemoryRegion, MemoryRegionType}, - BootloaderAcpiArg, BootloaderFramebufferArg, ACPI_RSDP, BOOTLOADER_NAME, FRAMEBUFFER_INFO, - INITRAMFS, KERNEL_COMMANDLINE, MEMORY_REGIONS, + kcmdline::KCmdlineArg, BootloaderAcpiArg, BootloaderFramebufferArg, }; use core::{arch::global_asm, mem::swap}; use spin::Once; @@ -17,8 +16,8 @@ const MULTIBOOT2_ENTRY_MAGIC: u32 = 0x36d76289; static MB2_INFO: Once = Once::new(); -fn init_bootloader_name() { - BOOTLOADER_NAME.call_once(|| { +fn init_bootloader_name(bootloader_name: &'static Once) { + bootloader_name.call_once(|| { MB2_INFO .get() .unwrap() @@ -30,8 +29,8 @@ fn init_bootloader_name() { }); } -fn init_kernel_commandline() { - KERNEL_COMMANDLINE.call_once(|| { +fn init_kernel_commandline(kernel_cmdline: &'static Once) { + kernel_cmdline.call_once(|| { MB2_INFO .get() .unwrap() @@ -39,11 +38,11 @@ fn init_kernel_commandline() { .expect("Kernel commandline not found from the Multiboot2 header!") .cmdline() .expect("UTF-8 error: failed to parse kernel commandline!") - .to_string() + .into() }); } -fn init_initramfs() { +fn init_initramfs(initramfs: &'static Once<&'static [u8]>) { let mb2_module_tag = MB2_INFO .get() .unwrap() @@ -58,11 +57,11 @@ fn init_initramfs() { base_addr }; let length = mb2_module_tag.module_size() as usize; - INITRAMFS.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) }); + initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) }); } -fn init_acpi_rsdp() { - ACPI_RSDP.call_once(|| { +fn init_acpi_arg(acpi: &'static Once) { + acpi.call_once(|| { if let Some(v2_tag) = MB2_INFO.get().unwrap().rsdp_v2_tag() { // check for rsdp v2 BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address()) @@ -75,9 +74,9 @@ fn init_acpi_rsdp() { }); } -fn init_framebuffer_info() { +fn init_framebuffer_info(framebuffer_arg: &'static Once) { let fb_tag = MB2_INFO.get().unwrap().framebuffer_tag().unwrap().unwrap(); - FRAMEBUFFER_INFO.call_once(|| BootloaderFramebufferArg { + framebuffer_arg.call_once(|| BootloaderFramebufferArg { address: fb_tag.address() as usize, width: fb_tag.width() as usize, height: fb_tag.height() as usize, @@ -97,7 +96,7 @@ impl From for MemoryRegionType { } } -fn init_memory_regions() { +fn init_memory_regions(memory_regions: &'static Once>) { // We should later use regions in `regions_unusable` to truncate all // regions in `regions_usable`. // The difference is that regions in `regions_usable` could be used by @@ -179,7 +178,7 @@ fn init_memory_regions() { } // Initialize with regions_unusable + regions_src - MEMORY_REGIONS.call_once(move || { + memory_regions.call_once(move || { let mut all_regions = regions_unusable; all_regions.append(regions_src); all_regions @@ -188,13 +187,20 @@ fn init_memory_regions() { /// Initialize the global boot static varaiables in the boot module to allow /// other modules to get the boot information. -pub fn init_global_boot_statics() { - init_bootloader_name(); - init_kernel_commandline(); - init_initramfs(); - init_acpi_rsdp(); - init_framebuffer_info(); - init_memory_regions(); +pub fn init_boot_args( + bootloader_name: &'static Once, + kernel_cmdline: &'static Once, + initramfs: &'static Once<&'static [u8]>, + acpi: &'static Once, + framebuffer_arg: &'static Once, + memory_regions: &'static Once>, +) { + init_bootloader_name(bootloader_name); + init_kernel_commandline(kernel_cmdline); + init_initramfs(initramfs); + init_acpi_arg(acpi); + init_framebuffer_info(framebuffer_arg); + init_memory_regions(memory_regions); } // The entry point of kernel code, which should be defined by the package that diff --git a/framework/jinux-frame/src/arch/x86/kernel/acpi/mod.rs b/framework/jinux-frame/src/arch/x86/kernel/acpi/mod.rs index feffc7836..564212359 100644 --- a/framework/jinux-frame/src/arch/x86/kernel/acpi/mod.rs +++ b/framework/jinux-frame/src/arch/x86/kernel/acpi/mod.rs @@ -6,9 +6,10 @@ use core::{ ptr::NonNull, }; -use crate::arch::boot::{self, BootloaderAcpiArg}; +use crate::boot::{self, BootloaderAcpiArg}; use crate::vm::paddr_to_vaddr; use acpi::{sdt::SdtHeader, AcpiHandler, AcpiTable, AcpiTables}; +use alloc::borrow::ToOwned; use log::info; use spin::{Mutex, Once}; @@ -90,7 +91,7 @@ impl AcpiHandler for AcpiMemoryHandler { } pub fn init() { - let acpi_tables = match boot::get_acpi_rsdp() { + let acpi_tables = match boot::acpi_arg().to_owned() { BootloaderAcpiArg::Rsdp(addr) => unsafe { AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr as usize).unwrap() }, diff --git a/framework/jinux-frame/src/arch/x86/mod.rs b/framework/jinux-frame/src/arch/x86/mod.rs index 4b7dd298a..8c38425d6 100644 --- a/framework/jinux-frame/src/arch/x86/mod.rs +++ b/framework/jinux-frame/src/arch/x86/mod.rs @@ -16,7 +16,6 @@ use log::{info, warn}; pub(crate) fn before_all_init() { enable_common_cpu_features(); device::serial::init(); - boot::init(); } pub(crate) fn after_all_init() { diff --git a/framework/jinux-frame/src/boot/kcmdline.rs b/framework/jinux-frame/src/boot/kcmdline.rs new file mode 100644 index 000000000..6bf93df51 --- /dev/null +++ b/framework/jinux-frame/src/boot/kcmdline.rs @@ -0,0 +1,23 @@ +//! The module to parse kernel commandline arguments. +//! + +use alloc::string::String; + +/// The struct to store parsed kernel commandline arguments. +pub struct KCmdlineArg { + initproc: Option, +} + +// Define get APIs. +impl KCmdlineArg { + pub fn get_initproc(&self) -> Option<&str> { + self.initproc.as_deref() + } +} + +// Define the way to parse a string to `KCmdlineArg`. +impl From<&str> for KCmdlineArg { + fn from(cmdline: &str) -> Self { + KCmdlineArg { initproc: None } + } +} diff --git a/framework/jinux-frame/src/arch/x86/boot/memory_region.rs b/framework/jinux-frame/src/boot/memory_region.rs similarity index 100% rename from framework/jinux-frame/src/arch/x86/boot/memory_region.rs rename to framework/jinux-frame/src/boot/memory_region.rs diff --git a/framework/jinux-frame/src/boot/mod.rs b/framework/jinux-frame/src/boot/mod.rs new file mode 100644 index 000000000..c4c274c31 --- /dev/null +++ b/framework/jinux-frame/src/boot/mod.rs @@ -0,0 +1,78 @@ +//! The architecture-independent boot module, which provides a universal interface +//! from the bootloader to the rest of the framework. +//! + +use crate::arch::boot::init_boot_args; + +pub mod kcmdline; +use kcmdline::KCmdlineArg; + +pub mod memory_region; +use self::memory_region::MemoryRegion; + +use alloc::{string::String, vec::Vec}; +use spin::Once; + +/// The boot crate can choose either providing the raw RSDP physical address or +/// providing the RSDT/XSDT physical address after parsing RSDP. +/// This is because bootloaders differ in such behaviors. +#[derive(Copy, Clone, Debug)] +pub enum BootloaderAcpiArg { + /// Physical address of the RSDP. + Rsdp(usize), + /// Address of RSDT provided in RSDP v1. + Rsdt(usize), + /// Address of XSDT provided in RSDP v2+. + Xsdt(usize), +} + +/// The framebuffer arguments. +#[derive(Copy, Clone, Debug)] +pub struct BootloaderFramebufferArg { + pub address: usize, + pub width: usize, + pub height: usize, + /// Bits per pixel of the buffer. + pub bpp: usize, +} + +// Use a macro to simplify coding. +macro_rules! define_global_static_boot_arguments { + ( $( $lower:ident, $upper:ident, $typ:ty; )* ) => { + // Define statics and corresponding public get APIs. + $( + static $upper: Once<$typ> = Once::new(); + /// Macro generated public get API. + pub fn $lower() -> &'static $typ { + $upper.get().unwrap() + } + )* + // Produce a init function call. The init function must + // be defined in the `arch::boot` module conforming to this + // definition. + fn arch_init_boot_args() { + init_boot_args( $( &$upper, )* ); + } + }; +} + +// Define a series of static variable definitions and its APIs. The names in +// each line are: +// 1. The lowercase name of the variable, also the name of the get API; +// 2. the uppercase name of the variable; +// 3. the type of the variable. +define_global_static_boot_arguments!( + bootloader_name, BOOTLOADER_NAME, String; + kernel_cmdline, KERNEL_CMDLINE, KCmdlineArg; + initramfs, INITRAMFS, &'static [u8]; + acpi_arg, ACPI_ARG, BootloaderAcpiArg; + framebuffer_arg, FRAMEBUFFER_ARG, BootloaderFramebufferArg; + memory_regions, MEMORY_REGIONS, Vec; +); + +/// After initializing the boot module, the get functions could be called. +/// The initialization must be done after the heap is set and before physical +/// mappings are cancelled. +pub fn init() { + arch_init_boot_args(); +} diff --git a/framework/jinux-frame/src/lib.rs b/framework/jinux-frame/src/lib.rs index af77b889a..2cdfdf7bb 100644 --- a/framework/jinux-frame/src/lib.rs +++ b/framework/jinux-frame/src/lib.rs @@ -18,6 +18,7 @@ extern crate alloc; pub mod arch; +pub mod boot; pub mod bus; pub mod config; pub mod cpu; @@ -44,9 +45,10 @@ use trapframe::TrapFrame; static mut IRQ_CALLBACK_LIST: Vec = Vec::new(); pub fn init() { - vm::heap_allocator::init(); arch::before_all_init(); logger::init(); + vm::heap_allocator::init(); + boot::init(); vm::init(); trap::init(); arch::after_all_init(); diff --git a/framework/jinux-frame/src/vm/frame_allocator.rs b/framework/jinux-frame/src/vm/frame_allocator.rs index 6c51b20a1..c16cae0e5 100644 --- a/framework/jinux-frame/src/vm/frame_allocator.rs +++ b/framework/jinux-frame/src/vm/frame_allocator.rs @@ -4,7 +4,7 @@ use buddy_system_allocator::FrameAllocator; use log::info; use spin::Once; -use crate::arch::boot::memory_region::{MemoryRegion, MemoryRegionType}; +use crate::boot::memory_region::{MemoryRegion, MemoryRegionType}; use crate::{config::PAGE_SIZE, sync::SpinLock}; use super::{frame::VmFrameFlags, VmFrame}; diff --git a/framework/jinux-frame/src/vm/mod.rs b/framework/jinux-frame/src/vm/mod.rs index c5f957d7b..a6ea15710 100644 --- a/framework/jinux-frame/src/vm/mod.rs +++ b/framework/jinux-frame/src/vm/mod.rs @@ -26,10 +26,11 @@ pub use self::{ page_table::PageTable, }; +use alloc::borrow::ToOwned; use alloc::vec::Vec; use spin::Once; -use crate::arch::boot::memory_region::{MemoryRegion, MemoryRegionType}; +use crate::boot::memory_region::{MemoryRegion, MemoryRegionType}; /// Convert physical address to virtual address using offset, only available inside jinux-frame pub(crate) fn paddr_to_vaddr(pa: usize) -> usize { @@ -55,7 +56,7 @@ pub(crate) static MEMORY_REGIONS: Once> = Once::new(); pub static FRAMEBUFFER_REGIONS: Once> = Once::new(); pub(crate) fn init() { - let memory_regions = crate::arch::boot::get_memory_regions(); + let memory_regions = crate::boot::memory_regions().to_owned(); frame_allocator::init(&memory_regions); let mut framebuffer_regions = Vec::new(); diff --git a/services/comps/framebuffer/src/lib.rs b/services/comps/framebuffer/src/lib.rs index 366680bf6..7c36e92a4 100644 --- a/services/comps/framebuffer/src/lib.rs +++ b/services/comps/framebuffer/src/lib.rs @@ -12,7 +12,7 @@ use core::{ ops::{Index, IndexMut}, }; use font8x8::UnicodeFonts; -use jinux_frame::{arch::boot, config::PAGE_SIZE, io_mem::IoMem, sync::SpinLock, vm::VmIo}; +use jinux_frame::{boot, config::PAGE_SIZE, io_mem::IoMem, sync::SpinLock, vm::VmIo}; use spin::Once; #[init_component] diff --git a/services/libs/jinux-std/src/lib.rs b/services/libs/jinux-std/src/lib.rs index 3891e6beb..370dc7747 100644 --- a/services/libs/jinux-std/src/lib.rs +++ b/services/libs/jinux-std/src/lib.rs @@ -25,7 +25,7 @@ use crate::{ process::status::ProcessStatus, thread::{kernel_thread::KernelThreadExt, Thread}, }; -use jinux_frame::{arch::boot, exit_qemu}; +use jinux_frame::{boot, exit_qemu}; use process::Process; extern crate alloc; @@ -51,7 +51,7 @@ pub fn init() { driver::init(); net::init(); process::fifo_scheduler::init(); - fs::initramfs::init(boot::get_initramfs()).unwrap(); + fs::initramfs::init(boot::initramfs()).unwrap(); device::init().unwrap(); }