ostd/boot/mod.rs
1// SPDX-License-Identifier: MPL-2.0
2
3//! The architecture-independent boot module, which provides
4//! 1. a universal information getter interface from the bootloader to the
5//! rest of OSTD;
6//! 2. the routine booting into the actual kernel;
7//! 3. the routine booting the other processors in the SMP context.
8
9#![cfg_attr(
10 any(target_arch = "riscv64", target_arch = "loongarch64"),
11 expect(dead_code)
12)]
13
14pub mod memory_region;
15pub mod smp;
16
17use alloc::{
18 string::{String, ToString},
19 vec::Vec,
20};
21
22use memory_region::{MemoryRegion, MemoryRegionArray};
23use spin::Once;
24
25/// The boot information provided by the bootloader.
26pub struct BootInfo {
27 /// The name of the bootloader.
28 pub bootloader_name: String,
29 /// The kernel command line arguments.
30 pub kernel_cmdline: String,
31 /// The initial ramfs raw bytes.
32 pub initramfs: Option<&'static [u8]>,
33 /// The framebuffer arguments.
34 pub framebuffer_arg: Option<BootloaderFramebufferArg>,
35 /// The memory regions provided by the bootloader.
36 pub memory_regions: Vec<MemoryRegion>,
37}
38
39/// Gets the boot information.
40//
41// This function is usable after initialization with `init_after_heap`.
42pub fn boot_info() -> &'static BootInfo {
43 INFO.get().unwrap()
44}
45
46static INFO: Once<BootInfo> = Once::new();
47
48/// ACPI information from the bootloader.
49///
50/// The boot crate can choose either providing the raw RSDP physical address or
51/// providing the RSDT/XSDT physical address after parsing RSDP.
52/// This is because bootloaders differ in such behaviors.
53#[derive(Copy, Clone, Debug)]
54pub enum BootloaderAcpiArg {
55 /// The bootloader does not provide one, a manual search is needed.
56 NotProvided,
57 /// Physical address of the RSDP.
58 Rsdp(usize),
59 /// Address of RSDT provided in RSDP v1.
60 Rsdt(usize),
61 /// Address of XSDT provided in RSDP v2+.
62 Xsdt(usize),
63}
64
65/// The framebuffer arguments.
66#[derive(Copy, Clone, Debug)]
67pub struct BootloaderFramebufferArg {
68 /// The address of the buffer.
69 pub address: usize,
70 /// The width of the buffer.
71 pub width: usize,
72 /// The height of the buffer.
73 pub height: usize,
74 /// Bits per pixel of the buffer.
75 pub bpp: usize,
76}
77
78/*************************** Boot-time information ***************************/
79
80/// The boot-time boot information.
81///
82/// When supporting multiple boot protocols with a single build, the entrypoint
83/// and boot information getters are dynamically decided. The entry point
84/// function should initializer all arguments at [`EARLY_INFO`].
85///
86/// All the references in this structure should be valid in the boot context.
87/// After the kernel is booted, users should use [`BootInfo`] instead.
88pub(crate) struct EarlyBootInfo {
89 pub(crate) bootloader_name: &'static str,
90 pub(crate) kernel_cmdline: &'static str,
91 pub(crate) initramfs: Option<&'static [u8]>,
92 pub(crate) acpi_arg: BootloaderAcpiArg,
93 pub(crate) framebuffer_arg: Option<BootloaderFramebufferArg>,
94 pub(crate) memory_regions: MemoryRegionArray,
95}
96
97/// The boot-time information.
98pub(crate) static EARLY_INFO: Once<EarlyBootInfo> = Once::new();
99
100/// Initializes the boot information.
101///
102/// This function copies the boot-time accessible information to the heap to
103/// allow [`boot_info`] to work properly.
104pub(crate) fn init_after_heap() {
105 let boot_time_info = EARLY_INFO.get().unwrap();
106
107 INFO.call_once(|| BootInfo {
108 bootloader_name: boot_time_info.bootloader_name.to_string(),
109 kernel_cmdline: boot_time_info.kernel_cmdline.to_string(),
110 initramfs: boot_time_info.initramfs,
111 framebuffer_arg: boot_time_info.framebuffer_arg,
112 memory_regions: boot_time_info.memory_regions.to_vec(),
113 });
114}
115
116/// Calls the OSTD-user defined entrypoint of the actual kernel.
117///
118/// Any kernel that uses the `ostd` crate should define a function marked with
119/// `ostd::main` as the entrypoint.
120///
121/// This function should be only called from the bootloader-specific module.
122pub(crate) fn call_ostd_main() -> ! {
123 // The entry point of kernel code, which should be defined by the package that
124 // uses OSTD.
125 unsafe extern "Rust" {
126 fn __ostd_main() -> !;
127 }
128
129 // SAFETY: The function is called only once on the BSP.
130 unsafe { crate::init() };
131
132 // SAFETY: This external function is defined by the package that uses OSTD,
133 // which should be generated by the `ostd::main` macro. So it is safe.
134 unsafe {
135 __ostd_main();
136 }
137}