mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +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 font8x8::UnicodeFonts;
|
||||
use ostd::{
|
||||
boot::{self, memory_region::MemoryRegionType, memory_regions},
|
||||
boot::{boot_info, memory_region::MemoryRegionType},
|
||||
io_mem::IoMem,
|
||||
mm::{VmIo, PAGE_SIZE},
|
||||
sync::SpinLock,
|
||||
@ -36,9 +36,11 @@ pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
|
||||
#[allow(clippy::diverging_sub_expression)]
|
||||
pub(crate) fn init() {
|
||||
let mut writer = {
|
||||
let framebuffer = boot::framebuffer_arg();
|
||||
let Some(framebuffer) = boot_info().framebuffer_arg else {
|
||||
return;
|
||||
};
|
||||
let mut size = 0;
|
||||
for region in memory_regions().iter() {
|
||||
for region in boot_info().memory_regions.iter() {
|
||||
if region.typ() == MemoryRegionType::Framebuffer {
|
||||
size = region.len();
|
||||
}
|
||||
@ -56,9 +58,9 @@ pub(crate) fn init() {
|
||||
io_mem,
|
||||
x_pos: 0,
|
||||
y_pos: 0,
|
||||
bytes_per_pixel: (framebuffer.bpp / 8) as usize,
|
||||
width: framebuffer.width as usize,
|
||||
height: framebuffer.height as usize,
|
||||
bytes_per_pixel: (framebuffer.bpp / 8),
|
||||
width: framebuffer.width,
|
||||
height: framebuffer.height,
|
||||
buffer: buffer.leak(),
|
||||
}
|
||||
};
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
use ostd::{
|
||||
arch::qemu::{exit_qemu, QemuExitCode},
|
||||
boot,
|
||||
boot::boot_info,
|
||||
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
||||
};
|
||||
use process::Process;
|
||||
@ -96,7 +96,7 @@ pub fn init() {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
net::init();
|
||||
sched::init();
|
||||
fs::rootfs::init(boot::initramfs()).unwrap();
|
||||
fs::rootfs::init(boot_info().initramfs.expect("No initramfs found!")).unwrap();
|
||||
device::init().unwrap();
|
||||
syscall::init();
|
||||
vdso::init();
|
||||
@ -141,7 +141,7 @@ fn init_thread() {
|
||||
|
||||
print_banner();
|
||||
|
||||
let karg = boot::kernel_cmdline();
|
||||
let karg = &boot_info().kernel_cmdline;
|
||||
|
||||
let initproc = Process::spawn_user_process(
|
||||
karg.get_initproc_path().unwrap(),
|
||||
|
@ -7,7 +7,7 @@ mod tests {
|
||||
|
||||
#[ktest]
|
||||
fn it_works() {
|
||||
let memory_regions = ostd::boot::memory_regions();
|
||||
let memory_regions = &ostd::boot::boot_info().memory_regions;
|
||||
assert!(!memory_regions.is_empty());
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
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()
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
pub mod smp;
|
||||
|
||||
use alloc::string::String;
|
||||
use core::arch::global_asm;
|
||||
|
||||
use fdt::Fdt;
|
||||
@ -12,11 +11,7 @@ use spin::Once;
|
||||
|
||||
use crate::{
|
||||
boot::{
|
||||
kcmdline::KCmdlineArg,
|
||||
memory_region::{
|
||||
non_overlapping_regions_from, MemoryRegion, MemoryRegionArray, MemoryRegionType,
|
||||
MAX_REGIONS,
|
||||
},
|
||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||
},
|
||||
early_println,
|
||||
@ -28,32 +23,33 @@ global_asm!(include_str!("boot.S"));
|
||||
/// The Flattened Device Tree of the platform.
|
||||
pub static DEVICE_TREE: Once<Fdt> = Once::new();
|
||||
|
||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
bootloader_name.call_once(|| "Unknown".into());
|
||||
fn parse_bootloader_name() -> &'static str {
|
||||
"Unknown"
|
||||
}
|
||||
|
||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
||||
let bootargs = DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("");
|
||||
kernel_cmdline.call_once(|| bootargs.into());
|
||||
fn parse_kernel_commandline() -> &'static str {
|
||||
DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("")
|
||||
}
|
||||
|
||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
||||
fn parse_initramfs() -> Option<&'static [u8]> {
|
||||
let Some((start, end)) = parse_initramfs_range() else {
|
||||
return;
|
||||
return None;
|
||||
};
|
||||
|
||||
let base_va = paddr_to_vaddr(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>) {
|
||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
||||
fn parse_acpi_arg() -> BootloaderAcpiArg {
|
||||
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();
|
||||
|
||||
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)> {
|
||||
@ -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() };
|
||||
DEVICE_TREE.call_once(|| fdt);
|
||||
|
||||
crate::boot::register_boot_init_callbacks(
|
||||
init_bootloader_name,
|
||||
init_kernel_commandline,
|
||||
init_initramfs,
|
||||
init_acpi_arg,
|
||||
init_framebuffer_info,
|
||||
init_memory_regions,
|
||||
);
|
||||
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||
|
||||
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.
|
||||
//!
|
||||
|
||||
use alloc::{borrow::ToOwned, format, string::String};
|
||||
use core::ffi::CStr;
|
||||
|
||||
use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
|
||||
use spin::Once;
|
||||
|
||||
use crate::{
|
||||
boot::{
|
||||
kcmdline::KCmdlineArg,
|
||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||
},
|
||||
mm::kspace::{paddr_to_vaddr, LINEAR_MAPPING_BASE_VADDR},
|
||||
};
|
||||
|
||||
static BOOT_PARAMS: Once<BootParams> = Once::new();
|
||||
|
||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
let hdr = &BOOT_PARAMS.get().unwrap().hdr;
|
||||
fn parse_bootloader_name(boot_params: &BootParams) -> &str {
|
||||
let hdr = &boot_params.hdr;
|
||||
// The bootloaders have assigned IDs in Linux, see
|
||||
// https://www.kernel.org/doc/Documentation/x86/boot.txt
|
||||
// for details.
|
||||
let ext_str: String;
|
||||
let name = match hdr.type_of_loader {
|
||||
match hdr.type_of_loader {
|
||||
0x0 => "LILO", // (0x00 reserved for pre-2.00 bootloader)
|
||||
0x1 => "Loadlin",
|
||||
0x2 => "bootsect-loader", // (0x20, all other values reserved)
|
||||
@ -40,37 +34,27 @@ fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
0xB => "Qemu",
|
||||
0xC => "Arcturus Networks uCbootloader",
|
||||
0xD => "kexec-tools",
|
||||
0xE => {
|
||||
// Extended
|
||||
ext_str = format!(
|
||||
"Extended bootloader {}, version {}",
|
||||
(hdr.ext_loader_type + 0x10),
|
||||
(hdr.type_of_loader & 0x0f) + (hdr.ext_loader_ver << 4)
|
||||
);
|
||||
&ext_str
|
||||
}
|
||||
0xE => "Extended loader",
|
||||
0xF => "Special", // (0xFF = undefined)
|
||||
0x10 => "Reserved",
|
||||
0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
|
||||
0x12 => "OVMF UEFI virtualization stack",
|
||||
_ => "Unknown bootloader type!",
|
||||
}
|
||||
.to_owned();
|
||||
bootloader_name.call_once(|| name);
|
||||
}
|
||||
|
||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
||||
let cmdline_c_str: &CStr =
|
||||
unsafe { CStr::from_ptr(BOOT_PARAMS.get().unwrap().hdr.cmd_line_ptr as *const i8) };
|
||||
fn parse_kernel_commandline(boot_params: &BootParams) -> &str {
|
||||
// SAFETY: The pointer in the header points to a valid C string.
|
||||
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();
|
||||
kernel_cmdline.call_once(|| cmdline_str.into());
|
||||
cmdline_str
|
||||
}
|
||||
|
||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
||||
let hdr = &BOOT_PARAMS.get().unwrap().hdr;
|
||||
fn parse_initramfs(boot_params: &BootParams) -> Option<&[u8]> {
|
||||
let hdr = &boot_params.hdr;
|
||||
let ptr = hdr.ramdisk_image as usize;
|
||||
if ptr == 0 {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
// We must return a slice composed by VA since kernel should read everything in VA.
|
||||
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;
|
||||
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>) {
|
||||
let rsdp = BOOT_PARAMS.get().unwrap().acpi_rsdp_addr;
|
||||
fn parse_acpi_arg(boot_params: &BootParams) -> BootloaderAcpiArg {
|
||||
let rsdp = boot_params.acpi_rsdp_addr;
|
||||
if rsdp == 0 {
|
||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
||||
BootloaderAcpiArg::NotProvided
|
||||
} 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>) {
|
||||
let screen_info = &BOOT_PARAMS.get().unwrap().screen_info;
|
||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
||||
fn parse_framebuffer_info(boot_params: &BootParams) -> Option<BootloaderFramebufferArg> {
|
||||
let screen_info = boot_params.screen_info;
|
||||
if screen_info.lfb_base == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(BootloaderFramebufferArg {
|
||||
address: screen_info.lfb_base as usize,
|
||||
width: screen_info.lfb_width as usize,
|
||||
height: screen_info.lfb_height as usize,
|
||||
bpp: screen_info.lfb_depth as usize,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
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 boot_params = BOOT_PARAMS.get().unwrap();
|
||||
|
||||
// Add regions from E820.
|
||||
let num_entries = boot_params.e820_entries as usize;
|
||||
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();
|
||||
|
||||
memory_regions.call_once(|| regions.into_non_overlapping());
|
||||
regions.into_non_overlapping()
|
||||
}
|
||||
|
||||
/// The entry point of the Rust code portion of Asterinas.
|
||||
#[no_mangle]
|
||||
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);
|
||||
BOOT_PARAMS.call_once(|| params);
|
||||
crate::boot::register_boot_init_callbacks(
|
||||
init_bootloader_name,
|
||||
init_kernel_commandline,
|
||||
init_initramfs,
|
||||
init_acpi_arg,
|
||||
init_framebuffer_info,
|
||||
init_memory_regions,
|
||||
);
|
||||
crate::boot::call_ostd_main();
|
||||
|
||||
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||
|
||||
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||
bootloader_name: parse_bootloader_name(params),
|
||||
kernel_cmdline: parse_kernel_commandline(params),
|
||||
initramfs: parse_initramfs(params),
|
||||
acpi_arg: parse_acpi_arg(params),
|
||||
framebuffer_arg: parse_framebuffer_info(params),
|
||||
memory_regions: parse_memory_regions(params),
|
||||
});
|
||||
|
||||
call_ostd_main();
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::string::String;
|
||||
use core::arch::global_asm;
|
||||
|
||||
use spin::Once;
|
||||
|
||||
use crate::{
|
||||
boot::{
|
||||
kcmdline::KCmdlineArg,
|
||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||
},
|
||||
@ -21,55 +17,48 @@ global_asm!(include_str!("header.S"));
|
||||
|
||||
pub(super) const MULTIBOOT_ENTRY_MAGIC: u32 = 0x2BADB002;
|
||||
|
||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
bootloader_name.call_once(|| {
|
||||
let mut name = "";
|
||||
let info = MB1_INFO.get().unwrap();
|
||||
if info.boot_loader_name != 0 {
|
||||
// SAFETY: the bootloader name is C-style zero-terminated string.
|
||||
unsafe {
|
||||
let cstr = paddr_to_vaddr(info.boot_loader_name as usize) as *const u8;
|
||||
let mut len = 0;
|
||||
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");
|
||||
fn parse_bootloader_name(mb1_info: &MultibootLegacyInfo) -> &str {
|
||||
let mut name = "Unknown Multiboot loader";
|
||||
if mb1_info.boot_loader_name != 0 {
|
||||
// SAFETY: the bootloader name is C-style zero-terminated string.
|
||||
unsafe {
|
||||
let cstr = paddr_to_vaddr(mb1_info.boot_loader_name as usize) as *const u8;
|
||||
let mut len = 0;
|
||||
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.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
|
||||
let (start, end) = unsafe {
|
||||
(
|
||||
@ -84,32 +73,33 @@ fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
||||
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.
|
||||
// TODO: What about UEFI?
|
||||
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
||||
BootloaderAcpiArg::NotProvided
|
||||
}
|
||||
|
||||
fn init_framebuffer_info(framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {
|
||||
let info = MB1_INFO.get().unwrap();
|
||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
||||
address: info.framebuffer_table.addr as usize,
|
||||
width: info.framebuffer_table.width as usize,
|
||||
height: info.framebuffer_table.height as usize,
|
||||
bpp: info.framebuffer_table.bpp as usize,
|
||||
});
|
||||
fn parse_framebuffer_info(mb1_info: &MultibootLegacyInfo) -> Option<BootloaderFramebufferArg> {
|
||||
if mb1_info.framebuffer_table.addr == 0 {
|
||||
return None;
|
||||
}
|
||||
Some(BootloaderFramebufferArg {
|
||||
address: mb1_info.framebuffer_table.addr 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 info = MB1_INFO.get().unwrap();
|
||||
|
||||
// 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 region = MemoryRegion::new(
|
||||
start.try_into().unwrap(),
|
||||
@ -121,10 +111,10 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
||||
|
||||
// Add the framebuffer region.
|
||||
let fb = BootloaderFramebufferArg {
|
||||
address: info.framebuffer_table.addr as usize,
|
||||
width: info.framebuffer_table.width as usize,
|
||||
height: info.framebuffer_table.height as usize,
|
||||
bpp: info.framebuffer_table.bpp as usize,
|
||||
address: mb1_info.framebuffer_table.addr 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,
|
||||
};
|
||||
regions
|
||||
.push(MemoryRegion::new(
|
||||
@ -138,8 +128,8 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
||||
regions.push(MemoryRegion::kernel()).unwrap();
|
||||
|
||||
// Add the initramfs area.
|
||||
if info.mods_count != 0 {
|
||||
let modules_addr = info.mods_addr as usize;
|
||||
if mb1_info.mods_count != 0 {
|
||||
let modules_addr = mb1_info.mods_addr as usize;
|
||||
// We only use one module
|
||||
let (start, end) = unsafe {
|
||||
(
|
||||
@ -165,8 +155,7 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Initialize with non-overlapping regions.
|
||||
memory_regions.call_once(move || regions.into_non_overlapping());
|
||||
regions.into_non_overlapping()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[no_mangle]
|
||||
unsafe extern "sysv64" fn __multiboot_entry(boot_magic: u32, boot_params: u64) -> ! {
|
||||
assert_eq!(boot_magic, MULTIBOOT_ENTRY_MAGIC);
|
||||
MB1_INFO.call_once(|| &*(paddr_to_vaddr(boot_params as usize) as *const MultibootLegacyInfo));
|
||||
crate::boot::register_boot_init_callbacks(
|
||||
init_bootloader_name,
|
||||
init_kernel_commandline,
|
||||
init_initramfs,
|
||||
init_acpi_arg,
|
||||
init_framebuffer_info,
|
||||
init_memory_regions,
|
||||
);
|
||||
crate::boot::call_ostd_main();
|
||||
let mb1_info =
|
||||
unsafe { &*(paddr_to_vaddr(boot_params as usize) as *const MultibootLegacyInfo) };
|
||||
|
||||
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||
|
||||
EARLY_INFO.call_once(|| EarlyBootInfo {
|
||||
bootloader_name: parse_bootloader_name(mb1_info),
|
||||
kernel_cmdline: parse_kernel_commandline(mb1_info),
|
||||
initramfs: parse_initramfs(mb1_info),
|
||||
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
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use core::arch::global_asm;
|
||||
|
||||
use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
||||
@ -8,7 +7,6 @@ use spin::Once;
|
||||
|
||||
use crate::{
|
||||
boot::{
|
||||
kcmdline::KCmdlineArg,
|
||||
memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
|
||||
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||
},
|
||||
@ -21,67 +19,57 @@ pub(super) const MULTIBOOT2_ENTRY_MAGIC: u32 = 0x36d76289;
|
||||
|
||||
static MB2_INFO: Once<BootInformation> = Once::new();
|
||||
|
||||
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||
bootloader_name.call_once(|| {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.boot_loader_name_tag()
|
||||
.expect("Bootloader name not found from the Multiboot2 header!")
|
||||
.name()
|
||||
.expect("UTF-8 error: failed to parse bootloader name!")
|
||||
.to_string()
|
||||
});
|
||||
fn parse_bootloader_name() -> &'static str {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.boot_loader_name_tag()
|
||||
.expect("Bootloader name not found from the Multiboot2 header!")
|
||||
.name()
|
||||
.expect("UTF-8 error: failed to parse bootloader name!")
|
||||
}
|
||||
|
||||
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
||||
kernel_cmdline.call_once(|| {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.command_line_tag()
|
||||
.expect("Kernel command-line not found from the Multiboot2 header!")
|
||||
.cmdline()
|
||||
.expect("UTF-8 error: failed to parse kernel command-line!")
|
||||
.into()
|
||||
});
|
||||
fn parse_kernel_commandline() -> &'static str {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.command_line_tag()
|
||||
.expect("Kernel command-line not found from the Multiboot2 header!")
|
||||
.cmdline()
|
||||
.expect("UTF-8 error: failed to parse kernel command-line!")
|
||||
}
|
||||
|
||||
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
||||
let Some(mb2_module_tag) = MB2_INFO.get().unwrap().module_tags().next() else {
|
||||
return;
|
||||
};
|
||||
fn parse_initramfs() -> Option<&'static [u8]> {
|
||||
let mb2_module_tag = MB2_INFO.get().unwrap().module_tags().next()?;
|
||||
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.
|
||||
let base_va = paddr_to_vaddr(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) });
|
||||
Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) })
|
||||
}
|
||||
|
||||
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
||||
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())
|
||||
} else if let Some(v1_tag) = MB2_INFO.get().unwrap().rsdp_v1_tag() {
|
||||
// fall back to rsdp v1
|
||||
BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
|
||||
} else {
|
||||
panic!("No ACPI RDSP information found!");
|
||||
}
|
||||
});
|
||||
fn parse_acpi_arg() -> BootloaderAcpiArg {
|
||||
if let Some(v2_tag) = MB2_INFO.get().unwrap().rsdp_v2_tag() {
|
||||
// check for rsdp v2
|
||||
BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address())
|
||||
} else if let Some(v1_tag) = MB2_INFO.get().unwrap().rsdp_v1_tag() {
|
||||
// fall back to rsdp v1
|
||||
BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
|
||||
} else {
|
||||
BootloaderAcpiArg::NotProvided
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return;
|
||||
return None;
|
||||
};
|
||||
framebuffer_arg.call_once(|| BootloaderFramebufferArg {
|
||||
Some(BootloaderFramebufferArg {
|
||||
address: fb_tag.address() as usize,
|
||||
width: fb_tag.width() as usize,
|
||||
height: fb_tag.height() as usize,
|
||||
bpp: fb_tag.bpp() as usize,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
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 mb2_info = MB2_INFO.get().unwrap();
|
||||
@ -158,8 +146,7 @@ fn init_memory_regions(memory_regions: &'static Once<MemoryRegionArray>) {
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Initialize with non-overlapping regions.
|
||||
memory_regions.call_once(move || regions.into_non_overlapping());
|
||||
regions.into_non_overlapping()
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
BootInformation::load(boot_params as *const BootInformationHeader).unwrap()
|
||||
});
|
||||
crate::boot::register_boot_init_callbacks(
|
||||
init_bootloader_name,
|
||||
init_kernel_commandline,
|
||||
init_initramfs,
|
||||
init_acpi_arg,
|
||||
init_framebuffer_info,
|
||||
init_memory_regions,
|
||||
);
|
||||
crate::boot::call_ostd_main();
|
||||
|
||||
use crate::boot::{call_ostd_main, EarlyBootInfo, EARLY_INFO};
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
pub mod dmar;
|
||||
pub mod remapping;
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use acpi::{rsdp::Rsdp, AcpiHandler, AcpiTables};
|
||||
@ -43,7 +42,7 @@ impl AcpiHandler for AcpiMemoryHandler {
|
||||
}
|
||||
|
||||
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 {
|
||||
AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr).unwrap()
|
||||
},
|
||||
|
@ -1,7 +1,5 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
//! The architecture-independent boot module, which provides
|
||||
//! 1. a universal information getter interface from the bootloader to the
|
||||
//! rest of OSTD;
|
||||
@ -12,12 +10,35 @@ pub mod kcmdline;
|
||||
pub mod memory_region;
|
||||
pub mod smp;
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use kcmdline::KCmdlineArg;
|
||||
use memory_region::{MemoryRegion, MemoryRegionArray};
|
||||
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.
|
||||
///
|
||||
@ -49,66 +70,41 @@ pub struct BootloaderFramebufferArg {
|
||||
pub bpp: usize,
|
||||
}
|
||||
|
||||
macro_rules! define_global_static_boot_arguments {
|
||||
( $( $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()
|
||||
}
|
||||
)*
|
||||
/*************************** Boot-time information ***************************/
|
||||
|
||||
struct BootInitCallBacks {
|
||||
$( $lower: fn(&'static Once<$typ>) -> (), )*
|
||||
}
|
||||
|
||||
static BOOT_INIT_CALLBACKS: Once<BootInitCallBacks> = Once::new();
|
||||
|
||||
/// The macro generated boot init callbacks registering interface.
|
||||
///
|
||||
/// For the introduction of a new boot protocol, the entry point could be a novel
|
||||
/// one. The entry point function should register all the boot initialization
|
||||
/// methods before `ostd::main` is called. A boot initialization method takes a
|
||||
/// reference of the global static boot information variable and initialize it,
|
||||
/// so that the boot information it represents could be accessed in the kernel
|
||||
/// anywhere.
|
||||
///
|
||||
/// 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); )*
|
||||
}
|
||||
};
|
||||
/// The boot-time boot information.
|
||||
///
|
||||
/// When supporting multiple boot protocols with a single build, the entrypoint
|
||||
/// and boot information getters are dynamically decided. The entry point
|
||||
/// function should initializer all arguments at [`EARLY_INFO`].
|
||||
///
|
||||
/// All the references in this structure should be valid in the boot context.
|
||||
/// After the kernel is booted, users should use [`BootInfo`] instead.
|
||||
pub(crate) struct EarlyBootInfo {
|
||||
pub(crate) bootloader_name: &'static str,
|
||||
pub(crate) kernel_cmdline: &'static str,
|
||||
pub(crate) initramfs: Option<&'static [u8]>,
|
||||
pub(crate) acpi_arg: BootloaderAcpiArg,
|
||||
pub(crate) framebuffer_arg: Option<BootloaderFramebufferArg>,
|
||||
pub(crate) memory_regions: MemoryRegionArray,
|
||||
}
|
||||
|
||||
// Define a series of static variables and their getter APIs.
|
||||
define_global_static_boot_arguments!(
|
||||
// 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 boot-time information.
|
||||
pub(crate) static EARLY_INFO: Once<EarlyBootInfo> = Once::new();
|
||||
|
||||
/// The initialization method of the boot module.
|
||||
/// Initializes the runtime information.
|
||||
///
|
||||
/// 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() {
|
||||
call_all_boot_init_callbacks();
|
||||
/// This function allows the run-time getters to work properly.
|
||||
pub(crate) fn init() {
|
||||
let boot_time_info = EARLY_INFO.get().unwrap();
|
||||
|
||||
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.
|
||||
|
@ -31,6 +31,7 @@ struct PerApInfo {
|
||||
// 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
|
||||
// to the frame allocator).
|
||||
#[allow(dead_code)]
|
||||
boot_stack_pages: Segment<KernelMeta>,
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ use core::str::FromStr;
|
||||
use log::{LevelFilter, Metadata, Record};
|
||||
use spin::Once;
|
||||
|
||||
use crate::boot::{kcmdline::ModuleArg, kernel_cmdline};
|
||||
use crate::boot::{boot_info, kcmdline::ModuleArg};
|
||||
|
||||
static LOGGER: Logger = Logger::new();
|
||||
|
||||
@ -82,7 +82,7 @@ pub(crate) fn init() {
|
||||
}
|
||||
|
||||
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 = 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(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 allocator = FrameAllocator::<32>::new();
|
||||
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.
|
||||
pub(crate) fn init() -> Segment<MetaPageMeta> {
|
||||
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()
|
||||
};
|
||||
|
||||
|
@ -134,7 +134,7 @@ pub static KERNEL_PAGE_TABLE: Once<PageTable<KernelMode, PageTableEntry, PagingC
|
||||
pub fn init_kernel_page_table(meta_pages: Segment<MetaPageMeta>) {
|
||||
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();
|
||||
|
||||
// Start to initialize the kernel page table.
|
||||
|
Reference in New Issue
Block a user