ostd/arch/x86/boot/linux_boot/
mod.rs1use linux_boot_params::{BootParams, E820Type, LINUX_BOOT_HEADER_MAGIC};
7
8use super::ToEarlyBootInfo;
9#[cfg(feature = "cvm_guest")]
10use crate::arch::init_cvm_guest;
11use crate::{
12 arch::if_tdx_enabled,
13 boot::{
14 BootloaderAcpiArg, BootloaderFramebufferArg,
15 memory_region::{MemoryRegion, MemoryRegionArray, MemoryRegionType},
16 },
17 mm::kspace::paddr_to_vaddr,
18};
19
20fn is_efi_boot(boot_params: &BootParams) -> bool {
21 const EFI32_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL32");
22 const EFI64_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"EL64");
23
24 let efi_info = boot_params.efi_info;
25 matches!(
26 efi_info.efi_loader_signature,
27 EFI32_LOADER_SIGNATURE | EFI64_LOADER_SIGNATURE
28 )
29}
30
31impl From<E820Type> for MemoryRegionType {
32 fn from(value: E820Type) -> Self {
33 match value {
34 E820Type::Ram => Self::Usable,
35 E820Type::Reserved => Self::Reserved,
36 E820Type::Acpi => Self::Reclaimable,
37 E820Type::Nvs => Self::NonVolatileSleep,
38 E820Type::Unusable => Self::BadMemory,
39 _ => Self::Reserved,
43 }
44 }
45}
46
47impl ToEarlyBootInfo for BootParams {
48 fn bootloader_name(&self) -> &'static str {
49 match self.hdr.type_of_loader {
53 0x0 => "LILO", 0x1 => "Loadlin",
55 0x2 => "bootsect-loader", 0x3 => "Syslinux",
57 0x4 => "Etherboot/gPXE/iPXE",
58 0x5 => "ELILO",
59 0x7 => "GRUB",
60 0x8 => "U-Boot",
61 0x9 => "Xen",
62 0xA => "Gujin",
63 0xB => "Qemu",
64 0xC => "Arcturus Networks uCbootloader",
65 0xD => "kexec-tools",
66 0xE => "Extended loader",
67 0xF => "Special", 0x10 => "Reserved",
69 0x11 => "Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>",
70 0x12 => "OVMF UEFI virtualization stack",
71 _ => "Unknown Linux Loader",
72 }
73 }
74
75 fn kernel_commandline(&self) -> Option<&'static str> {
76 if self.ext_cmd_line_ptr != 0 {
77 return None;
81 }
82
83 if self.hdr.cmd_line_ptr == 0 || self.hdr.cmdline_size == 0 {
84 return None;
85 }
86
87 let cmdline_ptr = paddr_to_vaddr(self.hdr.cmd_line_ptr as usize);
88 let cmdline_len = self.hdr.cmdline_size as usize;
89 let cmdline = unsafe { core::slice::from_raw_parts(cmdline_ptr as *const u8, cmdline_len) };
94
95 core::ffi::CStr::from_bytes_until_nul(cmdline)
97 .ok()?
98 .to_str()
99 .ok()
100 }
101
102 fn initramfs(&self) -> Option<&'static [u8]> {
103 if self.ext_ramdisk_image != 0 || self.ext_ramdisk_size != 0 {
104 return None;
106 }
107
108 if self.hdr.ramdisk_image == 0 || self.hdr.ramdisk_size == 0 {
109 return None;
110 }
111
112 let initramfs_ptr = paddr_to_vaddr(self.hdr.ramdisk_image as usize);
113 let initramfs_len = self.hdr.ramdisk_size as usize;
114 let initramfs =
119 unsafe { core::slice::from_raw_parts(initramfs_ptr as *const u8, initramfs_len) };
120
121 Some(initramfs)
122 }
123
124 fn acpi_arg(&self) -> BootloaderAcpiArg {
125 let rsdp = self.acpi_rsdp_addr;
126
127 if rsdp == 0 {
128 if is_efi_boot(self) {
129 BootloaderAcpiArg::NotProvided
130 } else {
131 BootloaderAcpiArg::ScanBios
132 }
133 } else {
134 BootloaderAcpiArg::Rsdp(rsdp.try_into().expect("RSDP address overflowed!"))
135 }
136 }
137
138 fn framebuffer_arg(&self) -> Option<BootloaderFramebufferArg> {
139 let screen_info = self.screen_info;
140
141 let address = screen_info.lfb_base as usize | ((screen_info.ext_lfb_base as usize) << 32);
142 if address == 0 {
143 return None;
144 }
145
146 Some(BootloaderFramebufferArg {
147 address,
148 width: screen_info.lfb_width as usize,
149 height: screen_info.lfb_height as usize,
150 bpp: screen_info.lfb_depth as usize,
151 })
152 }
153
154 fn memory_regions(
155 &self,
156 initramfs: Option<&'static [u8]>,
157 kernel_cmdline: Option<&'static str>,
158 framebuffer_arg: Option<BootloaderFramebufferArg>,
159 ) -> MemoryRegionArray {
160 let mut regions = MemoryRegionArray::new();
161
162 let num_entries = self.e820_entries as usize;
164 for e820_entry in &self.e820_table[0..num_entries] {
165 regions
166 .push(MemoryRegion::new(
167 e820_entry.addr.try_into().unwrap(),
168 e820_entry.size.try_into().unwrap(),
169 e820_entry.typ.into(),
170 ))
171 .unwrap();
172 }
173
174 if_tdx_enabled!({
180 regions
184 .push(MemoryRegion::new(
185 0x800000,
187 0x006000,
189 MemoryRegionType::NonVolatileSleep,
191 ))
192 .unwrap();
193 });
194
195 super::finish_memory_regions(regions, framebuffer_arg, initramfs, kernel_cmdline)
196 }
197}
198
199#[unsafe(no_mangle)]
208unsafe extern "sysv64" fn __linux_boot(params_ptr: *const BootParams) -> ! {
209 let params = unsafe { &*params_ptr };
210 assert_eq!({ params.hdr.header }, LINUX_BOOT_HEADER_MAGIC);
211
212 use crate::boot::{EARLY_INFO, start_kernel};
213
214 #[cfg(feature = "cvm_guest")]
215 init_cvm_guest();
216
217 EARLY_INFO.call_once(|| params.to_early_boot_info());
218
219 unsafe { start_kernel() };
222}