// SPDX-License-Identifier: MPL-2.0 //! The RISC-V boot module defines the entrypoints of Asterinas. pub mod smp; use core::arch::global_asm; use fdt::Fdt; use spin::Once; use crate::{ boot::{ memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType}, BootloaderAcpiArg, BootloaderFramebufferArg, }, early_println, mm::paddr_to_vaddr, }; global_asm!(include_str!("boot.S")); /// The Flattened Device Tree of the platform. pub static DEVICE_TREE: Once = Once::new(); fn parse_bootloader_name() -> &'static str { "Unknown" } fn parse_kernel_commandline() -> &'static str { DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("") } fn parse_initramfs() -> Option<&'static [u8]> { let Some((start, end)) = parse_initramfs_range() else { return None; }; let base_va = paddr_to_vaddr(start); let length = end - start; Some(unsafe { core::slice::from_raw_parts(base_va as *const u8, length) }) } fn parse_acpi_arg() -> BootloaderAcpiArg { BootloaderAcpiArg::NotProvided } fn parse_framebuffer_info() -> Option { None } fn parse_memory_regions() -> MemoryRegionArray { let mut regions = MemoryRegionArray::new(); for region in DEVICE_TREE.get().unwrap().memory().regions() { if region.size.unwrap_or(0) > 0 { regions.push(MemoryRegion::new( region.starting_address as usize, region.size.unwrap(), MemoryRegionType::Usable, )); } } if let Some(node) = DEVICE_TREE.get().unwrap().find_node("/reserved-memory") { for child in node.children() { if let Some(reg_iter) = child.reg() { for region in reg_iter { regions.push(MemoryRegion::new( region.starting_address as usize, region.size.unwrap(), MemoryRegionType::Reserved, )); } } } } // Add the kernel region. regions.push(MemoryRegion::kernel()); // Add the initramfs region. if let Some((start, end)) = parse_initramfs_range() { regions.push(MemoryRegion::new( start, end - start, MemoryRegionType::Module, )); } regions.into_non_overlapping() } fn parse_initramfs_range() -> Option<(usize, usize)> { let chosen = DEVICE_TREE.get().unwrap().find_node("/chosen").unwrap(); let initrd_start = chosen.property("linux,initrd-start")?.as_usize()?; let initrd_end = chosen.property("linux,initrd-end")?.as_usize()?; Some((initrd_start, initrd_end)) } /// The entry point of the Rust code portion of Asterinas. #[no_mangle] pub extern "C" fn riscv_boot(_hart_id: usize, device_tree_paddr: usize) -> ! { early_println!("Enter riscv_boot"); let device_tree_ptr = paddr_to_vaddr(device_tree_paddr) as *const u8; let fdt = unsafe { fdt::Fdt::from_ptr(device_tree_ptr).unwrap() }; DEVICE_TREE.call_once(|| fdt); 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(); }