ostd/arch/x86/boot/linux_boot/
mod.rs1use linux_boot_params::{BootParams, E820Type, EfiInfo, LINUX_BOOT_HEADER_MAGIC};
7
8use super::ToEarlyBootInfo;
9use crate::{
10 arch::if_tdx_enabled,
11 boot::{
12 BootloaderAcpiArg, BootloaderFramebufferArg,
13 memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
14 },
15 mm::kspace::paddr_to_vaddr,
16};
17
18fn is_efi_boot(boot_params: &BootParams) -> bool {
19 const EFI32_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL32");
20 const EFI64_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL64");
21
22 let efi_info = boot_params.efi_info;
23 matches!(
24 efi_info.efi_loader_signature,
25 EFI32_LOADER_SIGNATURE | EFI64_LOADER_SIGNATURE | EfiInfo::TDX_LOADER_SIGNATURE
26 )
27}
28
29impl From<E820Type> for MemoryRegionType {
30 fn from(value: E820Type) -> Self {
31 match value {
32 E820Type::RAM => Self::Usable,
33 E820Type::RESERVED => Self::Reserved,
34 E820Type::ACPI => Self::Reclaimable,
35 E820Type::NVS => Self::NonVolatileSleep,
36 E820Type::UNUSABLE => Self::BadMemory,
37 _ => Self::Reserved,
39 }
40 }
41}
42
43impl ToEarlyBootInfo for BootParams {
44 fn bootloader_name(&self) -> &'static str {
45 match self.hdr.type_of_loader {
49 0x0 => "LILO", 0x1 => "Loadlin",
51 0x2 => "bootsect-loader", 0x3 => "Syslinux",
53 0x4 => "Etherboot/gPXE/iPXE",
54 0x5 => "ELILO",
55 0x7 => "GRUB",
56 0x8 => "U-Boot",
57 0x9 => "Xen",
58 0xA => "Gujin",
59 0xB => "Qemu",
60 0xC => "Arcturus Networks uCbootloader",
61 0xD => "kexec-tools",
62 0xE => "Extended loader",
63 0xF => "Special", 0x10 => "Reserved",
65 0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
66 0x12 => "OVMF UEFI virtualization stack",
67 _ => "Unknown Linux Loader",
68 }
69 }
70
71 fn kernel_commandline(&self) -> Option<&'static str> {
72 if self.ext_cmd_line_ptr != 0 {
73 return None;
77 }
78
79 if self.hdr.cmd_line_ptr == 0 || self.hdr.cmdline_size == 0 {
80 return None;
81 }
82
83 let cmdline_ptr = paddr_to_vaddr(self.hdr.cmd_line_ptr as usize) as *const u8;
84 let cmdline_max_len = self.hdr.cmdline_size as usize;
85
86 let mut len = 0;
87 while len < cmdline_max_len {
88 if unsafe { cmdline_ptr.add(len).read() } == 0 {
92 break;
93 }
94 len += 1;
95 }
96
97 let cmdline = unsafe { core::slice::from_raw_parts(cmdline_ptr, len) };
102
103 core::str::from_utf8(cmdline).ok()
105 }
106
107 fn initramfs(&self) -> Option<&'static [u8]> {
108 if self.ext_ramdisk_image != 0 || self.ext_ramdisk_size != 0 {
109 return None;
111 }
112
113 if self.hdr.ramdisk_image == 0 || self.hdr.ramdisk_size == 0 {
114 return None;
115 }
116
117 let initramfs_ptr = paddr_to_vaddr(self.hdr.ramdisk_image as usize);
118 let initramfs_len = self.hdr.ramdisk_size as usize;
119 let initramfs =
124 unsafe { core::slice::from_raw_parts(initramfs_ptr as *const u8, initramfs_len) };
125
126 Some(initramfs)
127 }
128
129 fn acpi_arg(&self) -> BootloaderAcpiArg {
130 let rsdp = self.acpi_rsdp_addr;
131
132 if rsdp == 0 {
133 if is_efi_boot(self) {
134 BootloaderAcpiArg::NotProvided
135 } else {
136 BootloaderAcpiArg::ScanBios
137 }
138 } else {
139 BootloaderAcpiArg::Rsdp(rsdp.try_into().expect("RSDP address overflowed!"))
140 }
141 }
142
143 fn framebuffer_arg(&self) -> Option<BootloaderFramebufferArg> {
144 let screen_info = self.screen_info;
145
146 let address = screen_info.lfb_base as usize | ((screen_info.ext_lfb_base as usize) << 32);
147 if address == 0 {
148 return None;
149 }
150
151 Some(BootloaderFramebufferArg {
152 address,
153 width: screen_info.lfb_width as usize,
154 height: screen_info.lfb_height as usize,
155 bpp: screen_info.lfb_depth as usize,
156 })
157 }
158
159 fn memory_regions(
160 &self,
161 initramfs: Option<&'static [u8]>,
162 kernel_cmdline: Option<&'static str>,
163 framebuffer_arg: Option<BootloaderFramebufferArg>,
164 ) -> MemoryRegionArray {
165 let mut regions = MemoryRegionArray::new();
166
167 let num_entries = self.e820_entries as usize;
169 for e820_entry in &self.e820_table[0..num_entries] {
170 regions
171 .push(MemoryRegion::new(
172 e820_entry.addr.try_into().unwrap(),
173 e820_entry.size.try_into().unwrap(),
174 e820_entry.typ.into(),
175 ))
176 .unwrap();
177 }
178
179 if_tdx_enabled!({
180 if let Some(range) = crate::mm::frame::unaccepted::table_memory_range() {
181 regions
182 .push(MemoryRegion::new(
183 range.start,
184 range.len(),
185 MemoryRegionType::Reserved,
186 ))
187 .unwrap();
188 }
189 });
190
191 if_tdx_enabled!({
197 regions
201 .push(MemoryRegion::new(
202 0x800000,
204 0x006000,
206 MemoryRegionType::NonVolatileSleep,
208 ))
209 .unwrap();
210 });
211
212 super::finish_memory_regions(regions, framebuffer_arg, initramfs, kernel_cmdline)
213 }
214}
215
216#[unsafe(no_mangle)]
225unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
226 let params = unsafe { &*params_ptr };
227 assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
228
229 use crate::boot::{EARLY_INFO, start_kernel};
230
231 #[cfg(feature = "cvm_guest")]
232 crate::arch::init_cvm_guest(params);
233
234 EARLY_INFO.call_once(|| params.to_early_boot_info());
235
236 unsafe { start_kernel() };
239}