ostd/arch/x86/boot/multiboot2/
mod.rs1use core::arch::global_asm;
4
5use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
6
7use super::ToEarlyBootInfo;
8use crate::{
9 boot::{
10 BootloaderAcpiArg, BootloaderFramebufferArg,
11 memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
12 },
13 mm::{Paddr, kspace::paddr_to_vaddr},
14};
15
16global_asm!(include_str!("header.S"));
17
18unsafe fn make_str_vaddr_static(str: &str) -> &'static str {
19 let vaddr = paddr_to_vaddr(str.as_ptr() as Paddr);
20
21 let bytes = unsafe { core::slice::from_raw_parts(vaddr as *const u8, str.len()) };
23
24 core::str::from_utf8(bytes).unwrap()
25}
26
27fn is_efi_boot(mb2_info: &BootInformation) -> bool {
28 mb2_info.efi_sdt32_tag().is_some()
29 || mb2_info.efi_sdt64_tag().is_some()
30 || mb2_info.efi_memory_map_tag().is_some()
31 || mb2_info.efi_bs_not_exited_tag().is_some()
32 || mb2_info.efi_ih32_tag().is_some()
33 || mb2_info.efi_ih64_tag().is_some()
34}
35
36impl From<MemoryAreaType> for MemoryRegionType {
37 fn from(value: MemoryAreaType) -> Self {
38 match value {
39 MemoryAreaType::Available => Self::Usable,
40 MemoryAreaType::Reserved => Self::Reserved,
41 MemoryAreaType::AcpiAvailable => Self::Reclaimable,
42 MemoryAreaType::ReservedHibernate => Self::NonVolatileSleep,
43 MemoryAreaType::Defective => Self::BadMemory,
44 MemoryAreaType::Custom(_) => Self::Reserved,
45 }
46 }
47}
48
49impl ToEarlyBootInfo for BootInformation<'_> {
50 fn bootloader_name(&self) -> &'static str {
51 let Some(name) = self.boot_loader_name_tag().and_then(|tag| tag.name().ok()) else {
52 return "Unknown Multiboot2 Loader";
53 };
54
55 unsafe { make_str_vaddr_static(name) }
60 }
61
62 fn kernel_commandline(&self) -> Option<&'static str> {
63 let cmdline = self.command_line_tag()?.cmdline().ok()?;
64
65 Some(unsafe { make_str_vaddr_static(cmdline) })
70 }
71
72 fn initramfs(&self) -> Option<&'static [u8]> {
73 let module_tag = self.module_tags().next()?;
74
75 let initramfs_ptr = paddr_to_vaddr(module_tag.start_address() as usize);
76 let initramfs_len = module_tag.module_size() as usize;
77 let initramfs =
82 unsafe { core::slice::from_raw_parts(initramfs_ptr as *const u8, initramfs_len) };
83
84 Some(initramfs)
85 }
86
87 fn acpi_arg(&self) -> BootloaderAcpiArg {
88 if let Some(v2_tag) = self.rsdp_v2_tag() {
89 BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address())
91 } else if let Some(v1_tag) = self.rsdp_v1_tag() {
92 BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
94 } else if is_efi_boot(self) {
95 BootloaderAcpiArg::NotProvided
96 } else {
97 BootloaderAcpiArg::ScanBios
98 }
99 }
100
101 fn framebuffer_arg(&self) -> Option<BootloaderFramebufferArg> {
102 let fb_tag = self.framebuffer_tag()?.ok()?;
103
104 Some(BootloaderFramebufferArg {
105 address: fb_tag.address() as usize,
106 width: fb_tag.width() as usize,
107 height: fb_tag.height() as usize,
108 bpp: fb_tag.bpp() as usize,
109 })
110 }
111
112 fn memory_regions(
113 &self,
114 initramfs: Option<&'static [u8]>,
115 kernel_cmdline: Option<&'static str>,
116 framebuffer_arg: Option<BootloaderFramebufferArg>,
117 ) -> MemoryRegionArray {
118 let mut regions = MemoryRegionArray::new();
119
120 let memory_regions_tag = self
122 .memory_map_tag()
123 .expect("No memory regions are found in the Multiboot2 header!");
124 for region in memory_regions_tag.memory_areas() {
125 let start = region.start_address();
126 let end = region.end_address();
127 let area_typ: MemoryRegionType = MemoryAreaType::from(region.typ()).into();
128 regions
129 .push(MemoryRegion::new(
130 start.try_into().unwrap(),
131 (end - start).try_into().unwrap(),
132 area_typ,
133 ))
134 .unwrap();
135 }
136
137 if let Some(name) = self.boot_loader_name_tag().and_then(|tag| tag.name().ok()) {
139 regions
140 .push(MemoryRegion::new(
141 name.as_ptr() as usize,
142 name.len(),
143 MemoryRegionType::Reclaimable,
144 ))
145 .unwrap();
146 }
147
148 super::finish_memory_regions(regions, framebuffer_arg, initramfs, kernel_cmdline)
149 }
150}
151
152#[unsafe(no_mangle)]
161unsafe extern "sysv64" fn __multiboot2_entry(boot_magic: u32, boot_params: u64) -> ! {
162 assert_eq!(boot_magic, multiboot2::MAGIC);
163 let mb2_info =
164 unsafe { BootInformation::load(boot_params as *const BootInformationHeader).unwrap() };
165
166 use crate::boot::{EARLY_INFO, start_kernel};
167
168 EARLY_INFO.call_once(|| mb2_info.to_early_boot_info());
169
170 unsafe { start_kernel() };
173}