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