mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 12:06:43 +00:00
Refactor boot modules to make heap allocation explicit
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
51349a3da1
commit
397ce9652f
@ -15,7 +15,7 @@ use core::{
|
|||||||
use component::{init_component, ComponentInitError};
|
use component::{init_component, ComponentInitError};
|
||||||
use font8x8::UnicodeFonts;
|
use font8x8::UnicodeFonts;
|
||||||
use ostd::{
|
use ostd::{
|
||||||
boot::{self, memory_region::MemoryRegionType, memory_regions},
|
boot::{boot_info, memory_region::MemoryRegionType},
|
||||||
io_mem::IoMem,
|
io_mem::IoMem,
|
||||||
mm::{VmIo, PAGE_SIZE},
|
mm::{VmIo, PAGE_SIZE},
|
||||||
sync::SpinLock,
|
sync::SpinLock,
|
||||||
@ -36,9 +36,11 @@ pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
|
|||||||
#[allow(clippy::diverging_sub_expression)]
|
#[allow(clippy::diverging_sub_expression)]
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
let mut writer = {
|
let mut writer = {
|
||||||
let framebuffer = boot::framebuffer_arg();
|
let Some(framebuffer) = boot_info().framebuffer_arg else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for region in memory_regions().iter() {
|
for region in boot_info().memory_regions.iter() {
|
||||||
if region.typ() == MemoryRegionType::Framebuffer {
|
if region.typ() == MemoryRegionType::Framebuffer {
|
||||||
size = region.len();
|
size = region.len();
|
||||||
}
|
}
|
||||||
@ -56,9 +58,9 @@ pub(crate) fn init() {
|
|||||||
io_mem,
|
io_mem,
|
||||||
x_pos: 0,
|
x_pos: 0,
|
||||||
y_pos: 0,
|
y_pos: 0,
|
||||||
bytes_per_pixel: (framebuffer.bpp / 8) as usize,
|
bytes_per_pixel: (framebuffer.bpp / 8),
|
||||||
width: framebuffer.width as usize,
|
width: framebuffer.width,
|
||||||
height: framebuffer.height as usize,
|
height: framebuffer.height,
|
||||||
buffer: buffer.leak(),
|
buffer: buffer.leak(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
use ostd::{
|
use ostd::{
|
||||||
arch::qemu::{exit_qemu, QemuExitCode},
|
arch::qemu::{exit_qemu, QemuExitCode},
|
||||||
boot,
|
boot::boot_info,
|
||||||
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
||||||
};
|
};
|
||||||
use process::Process;
|
use process::Process;
|
||||||
@ -96,7 +96,7 @@ pub fn init() {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
net::init();
|
net::init();
|
||||||
sched::init();
|
sched::init();
|
||||||
fs::rootfs::init(boot::initramfs()).unwrap();
|
fs::rootfs::init(boot_info().initramfs.expect("No initramfs found!")).unwrap();
|
||||||
device::init().unwrap();
|
device::init().unwrap();
|
||||||
syscall::init();
|
syscall::init();
|
||||||
vdso::init();
|
vdso::init();
|
||||||
@ -141,7 +141,7 @@ fn init_thread() {
|
|||||||
|
|
||||||
print_banner();
|
print_banner();
|
||||||
|
|
||||||
let karg = boot::kernel_cmdline();
|
let karg = &boot_info().kernel_cmdline;
|
||||||
|
|
||||||
let initproc = Process::spawn_user_process(
|
let initproc = Process::spawn_user_process(
|
||||||
karg.get_initproc_path().unwrap(),
|
karg.get_initproc_path().unwrap(),
|
||||||
|
@ -7,7 +7,7 @@ mod tests {
|
|||||||
|
|
||||||
#[ktest]
|
#[ktest]
|
||||||
fn it_works() {
|
fn it_works() {
|
||||||
let memory_regions = ostd::boot::memory_regions();
|
let memory_regions = &ostd::boot::boot_info().memory_regions;
|
||||||
assert!(!memory_regions.is_empty());
|
assert!(!memory_regions.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
pub fn available_memory() -> usize {
|
pub fn available_memory() -> usize {
|
||||||
let regions = ostd::boot::memory_regions();
|
let regions = &ostd::boot::boot_info().memory_regions;
|
||||||
regions.iter().map(|region| region.len()).sum()
|
regions.iter().map(|region| region.len()).sum()
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
pub mod smp;
|
pub mod smp;
|
||||||
|
|
||||||
use alloc::string::String;
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
|
||||||
use fdt::Fdt;
|
use fdt::Fdt;
|
||||||
@ -12,11 +11,7 @@ use spin::Once;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||||
memory_region::{
|
|
||||||
non_overlapping_regions_from, MemoryRegion, MemoryRegionArray, MemoryRegionType,
|
|
||||||
MAX_REGIONS,
|
|
||||||
},
|
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
early_println,
|
early_println,
|
||||||
@ -28,32 +23,33 @@ global_asm!(include_str!("boot.S"));
|
|||||||
/// The Flattened Device Tree of the platform.
|
/// The Flattened Device Tree of the platform.
|
||||||
pub static DEVICE_TREE: Once<Fdt> = Once::new();
|
pub static DEVICE_TREE: Once<Fdt> = Once::new();
|
||||||
|
|
||||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
fn parse_bootloader_name() -> &'static str {
|
||||||
bootloader_name.call_once(|| "Unknown".into());
|
"Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
fn parse_kernel_commandline() -> &'static str {
|
||||||
let bootargs = DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("");
|
DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("")
|
||||||
kernel_cmdline.call_once(|| bootargs.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
fn parse_initramfs() -> Option<&'static [u8]> {
|
||||||
let Some((start, end)) = parse_initramfs_range() else {
|
let Some((start, end)) = parse_initramfs_range() else {
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let base_va = paddr_to_vaddr(start);
|
let base_va = paddr_to_vaddr(start);
|
||||||
let length = end - start;
|
let length = end - start;
|
||||||
initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
fn parse_acpi_arg() -> BootloaderAcpiArg {
|
||||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
BootloaderAcpiArg::NotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_framebuffer_info(_framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {}
|
fn parse_framebuffer_info() -> Option<BootloaderFramebufferArg> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
fn parse_memory_regions() -> MemoryRegionArray {
|
||||||
let mut regions = MemoryRegionArray::new();
|
let mut regions = MemoryRegionArray::new();
|
||||||
|
|
||||||
for region in DEVICE_TREE.get().unwrap().memory().regions() {
|
for region in DEVICE_TREE.get().unwrap().memory().regions() {
|
||||||
@ -92,7 +88,7 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_regions.call_once(|| regions.into_non_overlapping());
|
regions.into_non_overlapping()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_initramfs_range() -> Option<(usize, usize)> {
|
fn parse_initramfs_range() -> Option<(usize, usize)> {
|
||||||
@ -111,14 +107,16 @@ pub extern "C" fn riscv_boot(_hart_id: usize, device_tree_paddr: usize) -> ! {
|
|||||||
let fdt = unsafe { fdt::Fdt::from_ptr(device_tree_ptr).unwrap() };
|
let fdt = unsafe { fdt::Fdt::from_ptr(device_tree_ptr).unwrap() };
|
||||||
DEVICE_TREE.call_once(|| fdt);
|
DEVICE_TREE.call_once(|| fdt);
|
||||||
|
|
||||||
crate::boot::register_boot_init_callbacks(
|
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||||
init_bootloader_name,
|
|
||||||
init_kernel_commandline,
|
|
||||||
init_initramfs,
|
|
||||||
init_acpi_arg,
|
|
||||||
init_framebuffer_info,
|
|
||||||
init_memory_regions,
|
|
||||||
);
|
|
||||||
|
|
||||||
crate::boot::call_ostd_main();
|
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||||
|
bootloader_name: parse_bootloader_name(),
|
||||||
|
kernel_cmdline: parse_kernel_commandline(),
|
||||||
|
initramfs: parse_initramfs(),
|
||||||
|
acpi_arg: parse_acpi_arg(),
|
||||||
|
framebuffer_arg: parse_framebuffer_info(),
|
||||||
|
memory_regions: parse_memory_regions(),
|
||||||
|
});
|
||||||
|
|
||||||
|
call_ostd_main();
|
||||||
}
|
}
|
||||||
|
@ -3,30 +3,24 @@
|
|||||||
//! The Linux 64-bit Boot Protocol supporting module.
|
//! The Linux 64-bit Boot Protocol supporting module.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use alloc::{borrow::ToOwned, format, string::String};
|
|
||||||
use core::ffi::CStr;
|
use core::ffi::CStr;
|
||||||
|
|
||||||
use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
|
use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
|
||||||
use spin::Once;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
|
||||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
mm::kspace::{paddr_to_vaddr, LINEAR_MAPPING_BASE_VADDR},
|
mm::kspace::{paddr_to_vaddr, LINEAR_MAPPING_BASE_VADDR},
|
||||||
};
|
};
|
||||||
|
|
||||||
static BOOT_PARAMS: Once<BootParams> = Once::new();
|
fn parse_bootloader_name(boot_params: &BootParams) -> &str {
|
||||||
|
let hdr = &boot_params.hdr;
|
||||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
|
||||||
let hdr = &BOOT_PARAMS.get().unwrap().hdr;
|
|
||||||
// The bootloaders have assigned IDs in Linux, see
|
// The bootloaders have assigned IDs in Linux, see
|
||||||
// https://www.kernel.org/doc/Documentation/x86/boot.txt
|
// https://www.kernel.org/doc/Documentation/x86/boot.txt
|
||||||
// for details.
|
// for details.
|
||||||
let ext_str: String;
|
match hdr.type_of_loader {
|
||||||
let name = match hdr.type_of_loader {
|
|
||||||
0x0 => "LILO", // (0x00 reserved for pre-2.00 bootloader)
|
0x0 => "LILO", // (0x00 reserved for pre-2.00 bootloader)
|
||||||
0x1 => "Loadlin",
|
0x1 => "Loadlin",
|
||||||
0x2 => "bootsect-loader", // (0x20, all other values reserved)
|
0x2 => "bootsect-loader", // (0x20, all other values reserved)
|
||||||
@ -40,37 +34,27 @@ fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
|||||||
0xB => "Qemu",
|
0xB => "Qemu",
|
||||||
0xC => "Arcturus Networks uCbootloader",
|
0xC => "Arcturus Networks uCbootloader",
|
||||||
0xD => "kexec-tools",
|
0xD => "kexec-tools",
|
||||||
0xE => {
|
0xE => "Extended loader",
|
||||||
// Extended
|
|
||||||
ext_str = format!(
|
|
||||||
"Extended bootloader {}, version {}",
|
|
||||||
(hdr.ext_loader_type + 0x10),
|
|
||||||
(hdr.type_of_loader & 0x0f) + (hdr.ext_loader_ver << 4)
|
|
||||||
);
|
|
||||||
&ext_str
|
|
||||||
}
|
|
||||||
0xF => "Special", // (0xFF = undefined)
|
0xF => "Special", // (0xFF = undefined)
|
||||||
0x10 => "Reserved",
|
0x10 => "Reserved",
|
||||||
0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
|
0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
|
||||||
0x12 => "OVMF UEFI virtualization stack",
|
0x12 => "OVMF UEFI virtualization stack",
|
||||||
_ => "Unknown bootloader type!",
|
_ => "Unknown bootloader type!",
|
||||||
}
|
}
|
||||||
.to_owned();
|
|
||||||
bootloader_name.call_once(|| name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
fn parse_kernel_commandline(boot_params: &BootParams) -> &str {
|
||||||
let cmdline_c_str: &CStr =
|
// SAFETY: The pointer in the header points to a valid C string.
|
||||||
unsafe { CStr::from_ptr(BOOT_PARAMS.get().unwrap().hdr.cmd_line_ptr as *const i8) };
|
let cmdline_c_str: &CStr = unsafe { CStr::from_ptr(boot_params.hdr.cmd_line_ptr as *const i8) };
|
||||||
let cmdline_str = cmdline_c_str.to_str().unwrap();
|
let cmdline_str = cmdline_c_str.to_str().unwrap();
|
||||||
kernel_cmdline.call_once(|| cmdline_str.into());
|
cmdline_str
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
fn parse_initramfs(boot_params: &BootParams) -> Option<&[u8]> {
|
||||||
let hdr = &BOOT_PARAMS.get().unwrap().hdr;
|
let hdr = &boot_params.hdr;
|
||||||
let ptr = hdr.ramdisk_image as usize;
|
let ptr = hdr.ramdisk_image as usize;
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
// We must return a slice composed by VA since kernel should read everything in VA.
|
// We must return a slice composed by VA since kernel should read everything in VA.
|
||||||
let base_va = if ptr < LINEAR_MAPPING_BASE_VADDR {
|
let base_va = if ptr < LINEAR_MAPPING_BASE_VADDR {
|
||||||
@ -80,30 +64,32 @@ fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
|||||||
};
|
};
|
||||||
let length = hdr.ramdisk_size as usize;
|
let length = hdr.ramdisk_size as usize;
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
// SAFETY: The regions is reported as initramfs by the bootloader, so it should be valid.
|
||||||
|
Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
fn parse_acpi_arg(boot_params: &BootParams) -> BootloaderAcpiArg {
|
||||||
let rsdp = BOOT_PARAMS.get().unwrap().acpi_rsdp_addr;
|
let rsdp = boot_params.acpi_rsdp_addr;
|
||||||
if rsdp == 0 {
|
if rsdp == 0 {
|
||||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
BootloaderAcpiArg::NotProvided
|
||||||
} else {
|
} else {
|
||||||
acpi.call_once(|| {
|
BootloaderAcpiArg::Rsdp(rsdp.try_into().expect("RSDP address overflowed!"))
|
||||||
BootloaderAcpiArg::Rsdp(rsdp.try_into().expect("RSDP address overflowed!"))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_framebuffer_info(framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {
|
fn parse_framebuffer_info(boot_params: &BootParams) -> Option<BootloaderFramebufferArg> {
|
||||||
let screen_info = &BOOT_PARAMS.get().unwrap().screen_info;
|
let screen_info = boot_params.screen_info;
|
||||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
if screen_info.lfb_base == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(BootloaderFramebufferArg {
|
||||||
address: screen_info.lfb_base as usize,
|
address: screen_info.lfb_base as usize,
|
||||||
width: screen_info.lfb_width as usize,
|
width: screen_info.lfb_width as usize,
|
||||||
height: screen_info.lfb_height as usize,
|
height: screen_info.lfb_height as usize,
|
||||||
bpp: screen_info.lfb_depth as usize,
|
bpp: screen_info.lfb_depth as usize,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<E820Type> for MemoryRegionType {
|
impl From<E820Type> for MemoryRegionType {
|
||||||
@ -118,11 +104,9 @@ impl From<E820Type> for MemoryRegionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
fn parse_memory_regions(boot_params: &BootParams) -> MemoryRegionArray {
|
||||||
let mut regions = MemoryRegionArray::new();
|
let mut regions = MemoryRegionArray::new();
|
||||||
|
|
||||||
let boot_params = BOOT_PARAMS.get().unwrap();
|
|
||||||
|
|
||||||
// Add regions from E820.
|
// Add regions from E820.
|
||||||
let num_entries = boot_params.e820_entries as usize;
|
let num_entries = boot_params.e820_entries as usize;
|
||||||
for e820_entry in &boot_params.e820_table[0..num_entries] {
|
for e820_entry in &boot_params.e820_table[0..num_entries] {
|
||||||
@ -156,22 +140,25 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
memory_regions.call_once(|| regions.into_non_overlapping());
|
regions.into_non_overlapping()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point of the Rust code portion of Asterinas.
|
/// The entry point of the Rust code portion of Asterinas.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
|
unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
|
||||||
let params = *params_ptr;
|
let params = unsafe { &*params_ptr };
|
||||||
assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
|
assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
|
||||||
BOOT_PARAMS.call_once(|| params);
|
|
||||||
crate::boot::register_boot_init_callbacks(
|
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||||
init_bootloader_name,
|
|
||||||
init_kernel_commandline,
|
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||||
init_initramfs,
|
bootloader_name: parse_bootloader_name(params),
|
||||||
init_acpi_arg,
|
kernel_cmdline: parse_kernel_commandline(params),
|
||||||
init_framebuffer_info,
|
initramfs: parse_initramfs(params),
|
||||||
init_memory_regions,
|
acpi_arg: parse_acpi_arg(params),
|
||||||
);
|
framebuffer_arg: parse_framebuffer_info(params),
|
||||||
crate::boot::call_ostd_main();
|
memory_regions: parse_memory_regions(params),
|
||||||
|
});
|
||||||
|
|
||||||
|
call_ostd_main();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use alloc::string::String;
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
|
||||||
use spin::Once;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
|
||||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
@ -21,55 +17,48 @@ global_asm!(include_str!("header.S"));
|
|||||||
|
|
||||||
pub(super) const MULTIBOOT_ENTRY_MAGIC: u32 = 0x2BADB002;
|
pub(super) const MULTIBOOT_ENTRY_MAGIC: u32 = 0x2BADB002;
|
||||||
|
|
||||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
fn parse_bootloader_name(mb1_info: &MultibootLegacyInfo) -> &str {
|
||||||
bootloader_name.call_once(|| {
|
let mut name = "Unknown Multiboot loader";
|
||||||
let mut name = "";
|
if mb1_info.boot_loader_name != 0 {
|
||||||
let info = MB1_INFO.get().unwrap();
|
// SAFETY: the bootloader name is C-style zero-terminated string.
|
||||||
if info.boot_loader_name != 0 {
|
unsafe {
|
||||||
// SAFETY: the bootloader name is C-style zero-terminated string.
|
let cstr = paddr_to_vaddr(mb1_info.boot_loader_name as usize) as *const u8;
|
||||||
unsafe {
|
let mut len = 0;
|
||||||
let cstr = paddr_to_vaddr(info.boot_loader_name as usize) as *const u8;
|
while cstr.add(len).read() != 0 {
|
||||||
let mut len = 0;
|
len += 1;
|
||||||
while cstr.add(len).read() != 0 {
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = core::str::from_utf8(core::slice::from_raw_parts(cstr, len))
|
|
||||||
.expect("cmdline is not a utf-8 string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = core::str::from_utf8(core::slice::from_raw_parts(cstr, len))
|
||||||
|
.expect("cmdline is not a utf-8 string");
|
||||||
}
|
}
|
||||||
name.into()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
|
||||||
kernel_cmdline.call_once(|| {
|
|
||||||
let mut cmdline = "";
|
|
||||||
let info = MB1_INFO.get().unwrap();
|
|
||||||
if info.cmdline != 0 {
|
|
||||||
// SAFETY: the command line is C-style zero-terminated string.
|
|
||||||
unsafe {
|
|
||||||
let cstr = paddr_to_vaddr(info.cmdline as usize) as *const u8;
|
|
||||||
let mut len = 0;
|
|
||||||
while cstr.add(len).read() != 0 {
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdline = core::str::from_utf8(core::slice::from_raw_parts(cstr, len))
|
|
||||||
.expect("cmdline is not a utf-8 string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmdline.into()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
|
||||||
let info = MB1_INFO.get().unwrap();
|
|
||||||
// FIXME: We think all modules are initramfs, can this cause problems?
|
|
||||||
if info.mods_count == 0 {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
let modules_addr = info.mods_addr as usize;
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_kernel_commandline(mb1_info: &MultibootLegacyInfo) -> &str {
|
||||||
|
let mut cmdline = "";
|
||||||
|
if mb1_info.cmdline != 0 {
|
||||||
|
// SAFETY: the command line is C-style zero-terminated string.
|
||||||
|
unsafe {
|
||||||
|
let cstr = paddr_to_vaddr(mb1_info.cmdline as usize) as *const u8;
|
||||||
|
let mut len = 0;
|
||||||
|
while cstr.add(len).read() != 0 {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdline = core::str::from_utf8(core::slice::from_raw_parts(cstr, len))
|
||||||
|
.expect("cmdline is not a utf-8 string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmdline
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_initramfs(mb1_info: &MultibootLegacyInfo) -> Option<&[u8]> {
|
||||||
|
// FIXME: We think all modules are initramfs, can this cause problems?
|
||||||
|
if mb1_info.mods_count == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let modules_addr = mb1_info.mods_addr as usize;
|
||||||
// We only use one module
|
// We only use one module
|
||||||
let (start, end) = unsafe {
|
let (start, end) = unsafe {
|
||||||
(
|
(
|
||||||
@ -84,32 +73,33 @@ fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
|||||||
start
|
start
|
||||||
};
|
};
|
||||||
let length = end - start;
|
let length = end - start;
|
||||||
initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
|
||||||
|
Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
fn parse_acpi_arg(_mb1_info: &MultibootLegacyInfo) -> BootloaderAcpiArg {
|
||||||
// The multiboot protocol does not contain RSDP address.
|
// The multiboot protocol does not contain RSDP address.
|
||||||
// TODO: What about UEFI?
|
// TODO: What about UEFI?
|
||||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
BootloaderAcpiArg::NotProvided
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_framebuffer_info(framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {
|
fn parse_framebuffer_info(mb1_info: &MultibootLegacyInfo) -> Option<BootloaderFramebufferArg> {
|
||||||
let info = MB1_INFO.get().unwrap();
|
if mb1_info.framebuffer_table.addr == 0 {
|
||||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
return None;
|
||||||
address: info.framebuffer_table.addr as usize,
|
}
|
||||||
width: info.framebuffer_table.width as usize,
|
Some(BootloaderFramebufferArg {
|
||||||
height: info.framebuffer_table.height as usize,
|
address: mb1_info.framebuffer_table.addr as usize,
|
||||||
bpp: info.framebuffer_table.bpp as usize,
|
width: mb1_info.framebuffer_table.width as usize,
|
||||||
});
|
height: mb1_info.framebuffer_table.height as usize,
|
||||||
|
bpp: mb1_info.framebuffer_table.bpp as usize,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
fn parse_memory_regions(mb1_info: &MultibootLegacyInfo) -> MemoryRegionArray {
|
||||||
let mut regions = MemoryRegionArray::new();
|
let mut regions = MemoryRegionArray::new();
|
||||||
|
|
||||||
let info = MB1_INFO.get().unwrap();
|
|
||||||
|
|
||||||
// Add the regions in the multiboot protocol.
|
// Add the regions in the multiboot protocol.
|
||||||
for entry in info.get_memory_map() {
|
for entry in mb1_info.get_memory_map() {
|
||||||
let start = entry.base_addr();
|
let start = entry.base_addr();
|
||||||
let region = MemoryRegion::new(
|
let region = MemoryRegion::new(
|
||||||
start.try_into().unwrap(),
|
start.try_into().unwrap(),
|
||||||
@ -121,10 +111,10 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
|
|
||||||
// Add the framebuffer region.
|
// Add the framebuffer region.
|
||||||
let fb = BootloaderFramebufferArg {
|
let fb = BootloaderFramebufferArg {
|
||||||
address: info.framebuffer_table.addr as usize,
|
address: mb1_info.framebuffer_table.addr as usize,
|
||||||
width: info.framebuffer_table.width as usize,
|
width: mb1_info.framebuffer_table.width as usize,
|
||||||
height: info.framebuffer_table.height as usize,
|
height: mb1_info.framebuffer_table.height as usize,
|
||||||
bpp: info.framebuffer_table.bpp as usize,
|
bpp: mb1_info.framebuffer_table.bpp as usize,
|
||||||
};
|
};
|
||||||
regions
|
regions
|
||||||
.push(MemoryRegion::new(
|
.push(MemoryRegion::new(
|
||||||
@ -138,8 +128,8 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
regions.push(MemoryRegion::kernel()).unwrap();
|
regions.push(MemoryRegion::kernel()).unwrap();
|
||||||
|
|
||||||
// Add the initramfs area.
|
// Add the initramfs area.
|
||||||
if info.mods_count != 0 {
|
if mb1_info.mods_count != 0 {
|
||||||
let modules_addr = info.mods_addr as usize;
|
let modules_addr = mb1_info.mods_addr as usize;
|
||||||
// We only use one module
|
// We only use one module
|
||||||
let (start, end) = unsafe {
|
let (start, end) = unsafe {
|
||||||
(
|
(
|
||||||
@ -165,8 +155,7 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Initialize with non-overlapping regions.
|
regions.into_non_overlapping()
|
||||||
memory_regions.call_once(move || regions.into_non_overlapping());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Representation of Multiboot Information according to specification.
|
/// Representation of Multiboot Information according to specification.
|
||||||
@ -402,20 +391,23 @@ impl Iterator for MemoryEntryIter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MB1_INFO: Once<&'static MultibootLegacyInfo> = Once::new();
|
|
||||||
|
|
||||||
/// The entry point of Rust code called by inline asm.
|
/// The entry point of Rust code called by inline asm.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "sysv64" fn __multiboot_entry(boot_magic: u32, boot_params: u64) -> ! {
|
unsafe extern "sysv64" fn __multiboot_entry(boot_magic: u32, boot_params: u64) -> ! {
|
||||||
assert_eq!(boot_magic, MULTIBOOT_ENTRY_MAGIC);
|
assert_eq!(boot_magic, MULTIBOOT_ENTRY_MAGIC);
|
||||||
MB1_INFO.call_once(|| &*(paddr_to_vaddr(boot_params as usize) as *const MultibootLegacyInfo));
|
let mb1_info =
|
||||||
crate::boot::register_boot_init_callbacks(
|
unsafe { &*(paddr_to_vaddr(boot_params as usize) as *const MultibootLegacyInfo) };
|
||||||
init_bootloader_name,
|
|
||||||
init_kernel_commandline,
|
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||||
init_initramfs,
|
|
||||||
init_acpi_arg,
|
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||||
init_framebuffer_info,
|
bootloader_name: parse_bootloader_name(mb1_info),
|
||||||
init_memory_regions,
|
kernel_cmdline: parse_kernel_commandline(mb1_info),
|
||||||
);
|
initramfs: parse_initramfs(mb1_info),
|
||||||
crate::boot::call_ostd_main();
|
acpi_arg: parse_acpi_arg(mb1_info),
|
||||||
|
framebuffer_arg: parse_framebuffer_info(mb1_info),
|
||||||
|
memory_regions: parse_memory_regions(mb1_info),
|
||||||
|
});
|
||||||
|
|
||||||
|
call_ostd_main();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use alloc::string::{String, ToString};
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
|
||||||
use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
||||||
@ -8,7 +7,6 @@ use spin::Once;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
boot::{
|
boot::{
|
||||||
kcmdline::KCmdlineArg,
|
|
||||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
},
|
},
|
||||||
@ -21,67 +19,57 @@ pub(super) const MULTIBOOT2_ENTRY_MAGIC: u32 = 0x36d76289;
|
|||||||
|
|
||||||
static MB2_INFO: Once<BootInformation> = Once::new();
|
static MB2_INFO: Once<BootInformation> = Once::new();
|
||||||
|
|
||||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
fn parse_bootloader_name() -> &'static str {
|
||||||
bootloader_name.call_once(|| {
|
MB2_INFO
|
||||||
MB2_INFO
|
.get()
|
||||||
.get()
|
.unwrap()
|
||||||
.unwrap()
|
.boot_loader_name_tag()
|
||||||
.boot_loader_name_tag()
|
.expect("Bootloader name not found from the Multiboot2 header!")
|
||||||
.expect("Bootloader name not found from the Multiboot2 header!")
|
.name()
|
||||||
.name()
|
.expect("UTF-8 error: failed to parse bootloader name!")
|
||||||
.expect("UTF-8 error: failed to parse bootloader name!")
|
|
||||||
.to_string()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
fn parse_kernel_commandline() -> &'static str {
|
||||||
kernel_cmdline.call_once(|| {
|
MB2_INFO
|
||||||
MB2_INFO
|
.get()
|
||||||
.get()
|
.unwrap()
|
||||||
.unwrap()
|
.command_line_tag()
|
||||||
.command_line_tag()
|
.expect("Kernel command-line not found from the Multiboot2 header!")
|
||||||
.expect("Kernel command-line not found from the Multiboot2 header!")
|
.cmdline()
|
||||||
.cmdline()
|
.expect("UTF-8 error: failed to parse kernel command-line!")
|
||||||
.expect("UTF-8 error: failed to parse kernel command-line!")
|
|
||||||
.into()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
fn parse_initramfs() -> Option<&'static [u8]> {
|
||||||
let Some(mb2_module_tag) = MB2_INFO.get().unwrap().module_tags().next() else {
|
let mb2_module_tag = MB2_INFO.get().unwrap().module_tags().next()?;
|
||||||
return;
|
|
||||||
};
|
|
||||||
let base_addr = mb2_module_tag.start_address() as usize;
|
let base_addr = mb2_module_tag.start_address() as usize;
|
||||||
// We must return a slice composed by VA since kernel should read everything in VA.
|
// We must return a slice composed by VA since kernel should read everything in VA.
|
||||||
let base_va = paddr_to_vaddr(base_addr);
|
let base_va = paddr_to_vaddr(base_addr);
|
||||||
let length = mb2_module_tag.module_size() as usize;
|
let length = mb2_module_tag.module_size() as usize;
|
||||||
initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
fn parse_acpi_arg() -> BootloaderAcpiArg {
|
||||||
acpi.call_once(|| {
|
if let Some(v2_tag) = MB2_INFO.get().unwrap().rsdp_v2_tag() {
|
||||||
if let Some(v2_tag) = MB2_INFO.get().unwrap().rsdp_v2_tag() {
|
// check for rsdp v2
|
||||||
// check for rsdp v2
|
BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address())
|
||||||
BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address())
|
} else if let Some(v1_tag) = MB2_INFO.get().unwrap().rsdp_v1_tag() {
|
||||||
} else if let Some(v1_tag) = MB2_INFO.get().unwrap().rsdp_v1_tag() {
|
// fall back to rsdp v1
|
||||||
// fall back to rsdp v1
|
BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
|
||||||
BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
|
} else {
|
||||||
} else {
|
BootloaderAcpiArg::NotProvided
|
||||||
panic!("No ACPI RDSP information found!");
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_framebuffer_info(framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {
|
fn parse_framebuffer_info() -> Option<BootloaderFramebufferArg> {
|
||||||
let Some(Ok(fb_tag)) = MB2_INFO.get().unwrap().framebuffer_tag() else {
|
let Some(Ok(fb_tag)) = MB2_INFO.get().unwrap().framebuffer_tag() else {
|
||||||
return;
|
return None;
|
||||||
};
|
};
|
||||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
Some(BootloaderFramebufferArg {
|
||||||
address: fb_tag.address() as usize,
|
address: fb_tag.address() as usize,
|
||||||
width: fb_tag.width() as usize,
|
width: fb_tag.width() as usize,
|
||||||
height: fb_tag.height() as usize,
|
height: fb_tag.height() as usize,
|
||||||
bpp: fb_tag.bpp() as usize,
|
bpp: fb_tag.bpp() as usize,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MemoryAreaType> for MemoryRegionType {
|
impl From<MemoryAreaType> for MemoryRegionType {
|
||||||
@ -96,7 +84,7 @@ impl From<MemoryAreaType> for MemoryRegionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
fn parse_memory_regions() -> MemoryRegionArray {
|
||||||
let mut regions = MemoryRegionArray::new();
|
let mut regions = MemoryRegionArray::new();
|
||||||
|
|
||||||
let mb2_info = MB2_INFO.get().unwrap();
|
let mb2_info = MB2_INFO.get().unwrap();
|
||||||
@ -158,8 +146,7 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Initialize with non-overlapping regions.
|
regions.into_non_overlapping()
|
||||||
memory_regions.call_once(move || regions.into_non_overlapping());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The entry point of Rust code called by inline asm.
|
/// The entry point of Rust code called by inline asm.
|
||||||
@ -169,13 +156,17 @@ unsafe extern "sysv64" fn __multiboot2_entry(boot_magic: u32, boot_params: u64)
|
|||||||
MB2_INFO.call_once(|| unsafe {
|
MB2_INFO.call_once(|| unsafe {
|
||||||
BootInformation::load(boot_params as *const BootInformationHeader).unwrap()
|
BootInformation::load(boot_params as *const BootInformationHeader).unwrap()
|
||||||
});
|
});
|
||||||
crate::boot::register_boot_init_callbacks(
|
|
||||||
init_bootloader_name,
|
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||||
init_kernel_commandline,
|
|
||||||
init_initramfs,
|
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||||
init_acpi_arg,
|
bootloader_name: parse_bootloader_name(),
|
||||||
init_framebuffer_info,
|
kernel_cmdline: parse_kernel_commandline(),
|
||||||
init_memory_regions,
|
initramfs: parse_initramfs(),
|
||||||
);
|
acpi_arg: parse_acpi_arg(),
|
||||||
crate::boot::call_ostd_main();
|
framebuffer_arg: parse_framebuffer_info(),
|
||||||
|
memory_regions: parse_memory_regions(),
|
||||||
|
});
|
||||||
|
|
||||||
|
call_ostd_main();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
pub mod dmar;
|
pub mod dmar;
|
||||||
pub mod remapping;
|
pub mod remapping;
|
||||||
|
|
||||||
use alloc::borrow::ToOwned;
|
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use acpi::{rsdp::Rsdp, AcpiHandler, AcpiTables};
|
use acpi::{rsdp::Rsdp, AcpiHandler, AcpiTables};
|
||||||
@ -43,7 +42,7 @@ impl AcpiHandler for AcpiMemoryHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
let acpi_tables = match boot::acpi_arg().to_owned() {
|
let acpi_tables = match boot::EARLY_INFO.get().unwrap().acpi_arg {
|
||||||
BootloaderAcpiArg::Rsdp(addr) => unsafe {
|
BootloaderAcpiArg::Rsdp(addr) => unsafe {
|
||||||
AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
|
AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
//! The architecture-independent boot module, which provides
|
//! The architecture-independent boot module, which provides
|
||||||
//! 1. a universal information getter interface from the bootloader to the
|
//! 1. a universal information getter interface from the bootloader to the
|
||||||
//! rest of OSTD;
|
//! rest of OSTD;
|
||||||
@ -12,12 +10,35 @@ pub mod kcmdline;
|
|||||||
pub mod memory_region;
|
pub mod memory_region;
|
||||||
pub mod smp;
|
pub mod smp;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::{
|
||||||
|
string::{String, ToString},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
use kcmdline::KCmdlineArg;
|
use kcmdline::KCmdlineArg;
|
||||||
|
use memory_region::{MemoryRegion, MemoryRegionArray};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use self::memory_region::MemoryRegionArray;
|
/// The boot information provided by the bootloader.
|
||||||
|
pub struct BootInfo {
|
||||||
|
/// The name of the bootloader.
|
||||||
|
pub bootloader_name: String,
|
||||||
|
/// The kernel command line arguments.
|
||||||
|
pub kernel_cmdline: KCmdlineArg,
|
||||||
|
/// The initial ramfs raw bytes.
|
||||||
|
pub initramfs: Option<&'static [u8]>,
|
||||||
|
/// The framebuffer arguments.
|
||||||
|
pub framebuffer_arg: Option<BootloaderFramebufferArg>,
|
||||||
|
/// The memory regions provided by the bootloader.
|
||||||
|
pub memory_regions: Vec<MemoryRegion>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the boot information.
|
||||||
|
pub fn boot_info() -> &'static BootInfo {
|
||||||
|
INFO.get().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
static INFO: Once<BootInfo> = Once::new();
|
||||||
|
|
||||||
/// ACPI information from the bootloader.
|
/// ACPI information from the bootloader.
|
||||||
///
|
///
|
||||||
@ -49,66 +70,41 @@ pub struct BootloaderFramebufferArg {
|
|||||||
pub bpp: usize,
|
pub bpp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! define_global_static_boot_arguments {
|
/*************************** Boot-time information ***************************/
|
||||||
( $( $lower:ident, $upper:ident, $typ:ty; )* ) => {
|
|
||||||
// Define statics and corresponding public getter APIs.
|
|
||||||
$(
|
|
||||||
static $upper: Once<$typ> = Once::new();
|
|
||||||
/// Macro generated public getter API.
|
|
||||||
pub fn $lower() -> &'static $typ {
|
|
||||||
$upper.get().unwrap()
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
|
|
||||||
struct BootInitCallBacks {
|
/// The boot-time boot information.
|
||||||
$( $lower: fn(&'static Once<$typ>) -> (), )*
|
///
|
||||||
}
|
/// When supporting multiple boot protocols with a single build, the entrypoint
|
||||||
|
/// and boot information getters are dynamically decided. The entry point
|
||||||
static BOOT_INIT_CALLBACKS: Once<BootInitCallBacks> = Once::new();
|
/// function should initializer all arguments at [`EARLY_INFO`].
|
||||||
|
///
|
||||||
/// The macro generated boot init callbacks registering interface.
|
/// All the references in this structure should be valid in the boot context.
|
||||||
///
|
/// After the kernel is booted, users should use [`BootInfo`] instead.
|
||||||
/// For the introduction of a new boot protocol, the entry point could be a novel
|
pub(crate) struct EarlyBootInfo {
|
||||||
/// one. The entry point function should register all the boot initialization
|
pub(crate) bootloader_name: &'static str,
|
||||||
/// methods before `ostd::main` is called. A boot initialization method takes a
|
pub(crate) kernel_cmdline: &'static str,
|
||||||
/// reference of the global static boot information variable and initialize it,
|
pub(crate) initramfs: Option<&'static [u8]>,
|
||||||
/// so that the boot information it represents could be accessed in the kernel
|
pub(crate) acpi_arg: BootloaderAcpiArg,
|
||||||
/// anywhere.
|
pub(crate) framebuffer_arg: Option<BootloaderFramebufferArg>,
|
||||||
///
|
pub(crate) memory_regions: MemoryRegionArray,
|
||||||
/// The reason why the entry point function is not designed to directly initialize
|
|
||||||
/// the boot information variables is simply that the heap is not initialized at
|
|
||||||
/// that moment.
|
|
||||||
pub fn register_boot_init_callbacks($( $lower: fn(&'static Once<$typ>) -> (), )* ) {
|
|
||||||
BOOT_INIT_CALLBACKS.call_once(|| {
|
|
||||||
BootInitCallBacks { $( $lower, )* }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_all_boot_init_callbacks() {
|
|
||||||
let callbacks = &BOOT_INIT_CALLBACKS.get().unwrap();
|
|
||||||
$( (callbacks.$lower)(&$upper); )*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a series of static variables and their getter APIs.
|
/// The boot-time information.
|
||||||
define_global_static_boot_arguments!(
|
pub(crate) static EARLY_INFO: Once<EarlyBootInfo> = Once::new();
|
||||||
// Getter Names | Static Variables | Variable Types
|
|
||||||
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, MemoryRegionArray;
|
|
||||||
);
|
|
||||||
|
|
||||||
/// The initialization method of the boot module.
|
/// Initializes the runtime information.
|
||||||
///
|
///
|
||||||
/// After initializing the boot module, the get functions could be called.
|
/// This function allows the run-time getters to work properly.
|
||||||
/// The initialization must be done after the heap is set and before physical
|
pub(crate) fn init() {
|
||||||
/// mappings are cancelled.
|
let boot_time_info = EARLY_INFO.get().unwrap();
|
||||||
pub fn init() {
|
|
||||||
call_all_boot_init_callbacks();
|
INFO.call_once(|| BootInfo {
|
||||||
|
bootloader_name: boot_time_info.bootloader_name.to_string(),
|
||||||
|
kernel_cmdline: boot_time_info.kernel_cmdline.into(),
|
||||||
|
initramfs: boot_time_info.initramfs,
|
||||||
|
framebuffer_arg: boot_time_info.framebuffer_arg,
|
||||||
|
memory_regions: boot_time_info.memory_regions.to_vec(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls the OSTD-user defined entrypoint of the actual kernel.
|
/// Calls the OSTD-user defined entrypoint of the actual kernel.
|
||||||
|
@ -31,6 +31,7 @@ struct PerApInfo {
|
|||||||
// no longer be used, and the `Segment` can be deallocated (this problem also
|
// no longer be used, and the `Segment` can be deallocated (this problem also
|
||||||
// exists in the boot processor, but the memory it occupies should be returned
|
// exists in the boot processor, but the memory it occupies should be returned
|
||||||
// to the frame allocator).
|
// to the frame allocator).
|
||||||
|
#[allow(dead_code)]
|
||||||
boot_stack_pages: Segment<KernelMeta>,
|
boot_stack_pages: Segment<KernelMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use core::str::FromStr;
|
|||||||
use log::{LevelFilter, Metadata, Record};
|
use log::{LevelFilter, Metadata, Record};
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
||||||
use crate::boot::{kcmdline::ModuleArg, kernel_cmdline};
|
use crate::boot::{boot_info, kcmdline::ModuleArg};
|
||||||
|
|
||||||
static LOGGER: Logger = Logger::new();
|
static LOGGER: Logger = Logger::new();
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ pub(crate) fn init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_log_level() -> Option<LevelFilter> {
|
fn get_log_level() -> Option<LevelFilter> {
|
||||||
let module_args = kernel_cmdline().get_module_args("ostd")?;
|
let module_args = boot_info().kernel_cmdline.get_module_args("ostd")?;
|
||||||
|
|
||||||
let value = {
|
let value = {
|
||||||
let value = module_args.iter().find_map(|arg| match arg {
|
let value = module_args.iter().find_map(|arg| match arg {
|
||||||
|
@ -184,7 +184,7 @@ impl CountingFrameAllocator {
|
|||||||
pub(in crate::mm) static FRAME_ALLOCATOR: Once<SpinLock<CountingFrameAllocator>> = Once::new();
|
pub(in crate::mm) static FRAME_ALLOCATOR: Once<SpinLock<CountingFrameAllocator>> = Once::new();
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
let regions = crate::boot::memory_regions();
|
let regions = &crate::boot::EARLY_INFO.get().unwrap().memory_regions;
|
||||||
let mut total: usize = 0;
|
let mut total: usize = 0;
|
||||||
let mut allocator = FrameAllocator::<32>::new();
|
let mut allocator = FrameAllocator::<32>::new();
|
||||||
for region in regions.iter() {
|
for region in regions.iter() {
|
||||||
|
@ -246,7 +246,7 @@ impl_frame_meta_for!(MetaPageMeta);
|
|||||||
/// The function returns a list of `Frame`s containing the metadata.
|
/// The function returns a list of `Frame`s containing the metadata.
|
||||||
pub(crate) fn init() -> Segment<MetaPageMeta> {
|
pub(crate) fn init() -> Segment<MetaPageMeta> {
|
||||||
let max_paddr = {
|
let max_paddr = {
|
||||||
let regions = crate::boot::memory_regions();
|
let regions = &crate::boot::EARLY_INFO.get().unwrap().memory_regions;
|
||||||
regions.iter().map(|r| r.base() + r.len()).max().unwrap()
|
regions.iter().map(|r| r.base() + r.len()).max().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ pub static KERNEL_PAGE_TABLE: Once<PageTable<KernelMode, PageTableEntry, PagingC
|
|||||||
pub fn init_kernel_page_table(meta_pages: Segment<MetaPageMeta>) {
|
pub fn init_kernel_page_table(meta_pages: Segment<MetaPageMeta>) {
|
||||||
info!("Initializing the kernel page table");
|
info!("Initializing the kernel page table");
|
||||||
|
|
||||||
let regions = crate::boot::memory_regions();
|
let regions = &crate::boot::EARLY_INFO.get().unwrap().memory_regions;
|
||||||
let phys_mem_cap = regions.iter().map(|r| r.base() + r.len()).max().unwrap();
|
let phys_mem_cap = regions.iter().map(|r| r.base() + r.len()).max().unwrap();
|
||||||
|
|
||||||
// Start to initialize the kernel page table.
|
// Start to initialize the kernel page table.
|
||||||
|
Reference in New Issue
Block a user