ostd/boot/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
// SPDX-License-Identifier: MPL-2.0
//! The architecture-independent boot module, which provides
//! 1. a universal information getter interface from the bootloader to the
//! rest of OSTD;
//! 2. the routine booting into the actual kernel;
//! 3. the routine booting the other processors in the SMP context.
pub mod memory_region;
pub mod smp;
use alloc::{
string::{String, ToString},
vec::Vec,
};
use memory_region::{MemoryRegion, MemoryRegionArray};
use spin::Once;
/// 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: String,
/// 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.
//
// This function is usable after initialization with `init_after_heap`.
pub fn boot_info() -> &'static BootInfo {
INFO.get().unwrap()
}
static INFO: Once<BootInfo> = Once::new();
/// ACPI information from the bootloader.
///
/// 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 {
/// The bootloader does not provide one, a manual search is needed.
NotProvided,
/// 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 {
/// The address of the buffer.
pub address: usize,
/// The width of the buffer.
pub width: usize,
/// The height of the buffer.
pub height: usize,
/// Bits per pixel of the buffer.
pub bpp: usize,
}
/*************************** Boot-time information ***************************/
/// 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,
}
/// The boot-time information.
pub(crate) static EARLY_INFO: Once<EarlyBootInfo> = Once::new();
/// Initializes the boot information.
///
/// This function copies the boot-time accessible information to the heap to
/// allow [`boot_info`] to work properly.
pub(crate) fn init_after_heap() {
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.to_string(),
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.
///
/// Any kernel that uses the `ostd` crate should define a function marked with
/// `ostd::main` as the entrypoint.
///
/// This function should be only called from the bootloader-specific module.
pub(crate) fn call_ostd_main() -> ! {
// The entry point of kernel code, which should be defined by the package that
// uses OSTD.
extern "Rust" {
fn __ostd_main() -> !;
}
// SAFETY: The function is called only once on the BSP.
unsafe { crate::init() };
// SAFETY: This external function is defined by the package that uses OSTD,
// which should be generated by the `ostd::main` macro. So it is safe.
unsafe {
__ostd_main();
}
}