ostd/arch/x86/boot/linux_boot/
mod.rs1use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
7
8#[cfg(feature = "cvm_guest")]
9use crate::arch::init_cvm_guest;
10use crate::{
11 arch::if_tdx_enabled,
12 boot::{
13 BootloaderAcpiArg, BootloaderFramebufferArg,
14 memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
15 },
16 mm::kspace::paddr_to_vaddr,
17};
18
19fn parse_bootloader_name(boot_params: &BootParams) -> &str {
20 match boot_params.hdr.type_of_loader {
24 0x0 => "LILO", 0x1 => "Loadlin",
26 0x2 => "bootsect-loader", 0x3 => "Syslinux",
28 0x4 => "Etherboot/gPXE/iPXE",
29 0x5 => "ELILO",
30 0x7 => "GRUB",
31 0x8 => "U-Boot",
32 0x9 => "Xen",
33 0xA => "Gujin",
34 0xB => "Qemu",
35 0xC => "Arcturus Networks uCbootloader",
36 0xD => "kexec-tools",
37 0xE => "Extended loader",
38 0xF => "Special", 0x10 => "Reserved",
40 0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
41 0x12 => "OVMF UEFI virtualization stack",
42 _ => "Unknown Linux Loader",
43 }
44}
45
46fn parse_kernel_commandline(boot_params: &BootParams) -> Option<&str> {
47 if boot_params.ext_cmd_line_ptr != 0 {
48 return None;
52 }
53
54 if boot_params.hdr.cmd_line_ptr == 0 || boot_params.hdr.cmdline_size == 0 {
55 return None;
56 }
57
58 let cmdline_ptr = paddr_to_vaddr(boot_params.hdr.cmd_line_ptr as usize);
59 let cmdline_len = boot_params.hdr.cmdline_size as usize;
60 let cmdline = unsafe { core::slice::from_raw_parts(cmdline_ptr as *const u8, cmdline_len) };
62
63 core::ffi::CStr::from_bytes_until_nul(cmdline)
65 .ok()?
66 .to_str()
67 .ok()
68}
69
70fn parse_initramfs(boot_params: &BootParams) -> Option<&[u8]> {
71 if boot_params.ext_ramdisk_image != 0 || boot_params.ext_ramdisk_size != 0 {
72 return None;
74 }
75
76 if boot_params.hdr.ramdisk_image == 0 || boot_params.hdr.ramdisk_size == 0 {
77 return None;
78 }
79
80 let initramfs_ptr = paddr_to_vaddr(boot_params.hdr.ramdisk_image as usize);
81 let initramfs_len = boot_params.hdr.ramdisk_size as usize;
82 let initramfs =
84 unsafe { core::slice::from_raw_parts(initramfs_ptr as *const u8, initramfs_len) };
85
86 Some(initramfs)
87}
88
89fn parse_acpi_arg(boot_params: &BootParams) -> BootloaderAcpiArg {
90 let rsdp = boot_params.acpi_rsdp_addr;
91
92 if rsdp == 0 {
93 if is_efi_boot(boot_params) {
94 BootloaderAcpiArg::NotProvided
95 } else {
96 BootloaderAcpiArg::ScanBios
97 }
98 } else {
99 BootloaderAcpiArg::Rsdp(rsdp.try_into().expect("RSDP address overflowed!"))
100 }
101}
102
103fn is_efi_boot(boot_params: &BootParams) -> bool {
104 const EFI32_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL32");
105 const EFI64_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL64");
106
107 let efi_info = boot_params.efi_info;
108 matches!(
109 efi_info.efi_loader_signature,
110 EFI32_LOADER_SIGNATURE | EFI64_LOADER_SIGNATURE
111 )
112}
113
114fn parse_framebuffer_info(boot_params: &BootParams) -> Option<BootloaderFramebufferArg> {
115 let screen_info = boot_params.screen_info;
116
117 let address = screen_info.lfb_base as usize | ((screen_info.ext_lfb_base as usize) << 32);
118 if address == 0 {
119 return None;
120 }
121
122 Some(BootloaderFramebufferArg {
123 address,
124 width: screen_info.lfb_width as usize,
125 height: screen_info.lfb_height as usize,
126 bpp: screen_info.lfb_depth as usize,
127 })
128}
129
130impl From<E820Type> for MemoryRegionType {
131 fn from(value: E820Type) -> Self {
132 match value {
133 E820Type::Ram => Self::Usable,
134 E820Type::Reserved => Self::Reserved,
135 E820Type::Acpi => Self::Reclaimable,
136 E820Type::Nvs => Self::NonVolatileSleep,
137 E820Type::Unusable => Self::BadMemory,
138 _ => Self::Reserved,
142 }
143 }
144}
145
146fn parse_memory_regions(boot_params: &BootParams) -> MemoryRegionArray {
147 let mut regions = MemoryRegionArray::new();
148
149 let num_entries = boot_params.e820_entries as usize;
151 for e820_entry in &boot_params.e820_table[0..num_entries] {
152 regions
153 .push(MemoryRegion::new(
154 e820_entry.addr.try_into().unwrap(),
155 e820_entry.size.try_into().unwrap(),
156 e820_entry.typ.into(),
157 ))
158 .unwrap();
159 }
160
161 if let Some(fb) = parse_framebuffer_info(boot_params) {
163 regions.push(MemoryRegion::framebuffer(&fb)).unwrap();
164 }
165
166 regions.push(MemoryRegion::kernel()).unwrap();
168
169 if let Some(initramfs) = parse_initramfs(boot_params) {
171 regions.push(MemoryRegion::module(initramfs)).unwrap();
172 }
173
174 regions
176 .push(super::smp::reclaimable_memory_region())
177 .unwrap();
178
179 if let Some(kcmdline) = parse_kernel_commandline(boot_params) {
181 regions
182 .push(MemoryRegion::module(kcmdline.as_bytes()))
183 .unwrap();
184 }
185
186 if_tdx_enabled!({
192 regions
196 .push(MemoryRegion::new(
197 0x800000,
199 0x006000,
201 MemoryRegionType::NonVolatileSleep,
203 ))
204 .unwrap();
205 });
206
207 regions.into_non_overlapping()
208}
209
210#[unsafe(no_mangle)]
219unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
220 let params = unsafe { &*params_ptr };
221 assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
222
223 use crate::boot::{EARLY_INFO, EarlyBootInfo, start_kernel};
224
225 #[cfg(feature = "cvm_guest")]
226 init_cvm_guest();
227
228 EARLY_INFO.call_once(|| EarlyBootInfo {
229 bootloader_name: parse_bootloader_name(params),
230 kernel_cmdline: parse_kernel_commandline(params).unwrap_or(""),
231 initramfs: parse_initramfs(params),
232 acpi_arg: parse_acpi_arg(params),
233 framebuffer_arg: parse_framebuffer_info(params),
234 memory_regions: parse_memory_regions(params),
235 });
236
237 unsafe { start_kernel() };
240}