1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker
15*5225e6b1SAndroid Build Coastguard Worker //! Boot protocol implementation for x86 platforms.
16*5225e6b1SAndroid Build Coastguard Worker //!
17*5225e6b1SAndroid Build Coastguard Worker //! For linux, the library currently only supports bzimage and protocol version 2.06+.
18*5225e6b1SAndroid Build Coastguard Worker //! Specifically, modern memory layout is used, protected kernel is loaded to high address at
19*5225e6b1SAndroid Build Coastguard Worker //! 0x100000 and command line size can be greater than 255 characters.
20*5225e6b1SAndroid Build Coastguard Worker //!
21*5225e6b1SAndroid Build Coastguard Worker //! ~ ~
22*5225e6b1SAndroid Build Coastguard Worker //! | Protected-mode kernel |
23*5225e6b1SAndroid Build Coastguard Worker //! 100000 +------------------------+
24*5225e6b1SAndroid Build Coastguard Worker //! | I/O memory hole |
25*5225e6b1SAndroid Build Coastguard Worker //! 0A0000 +------------------------+
26*5225e6b1SAndroid Build Coastguard Worker //! | Reserved for BIOS | Leave as much as possible unused
27*5225e6b1SAndroid Build Coastguard Worker //! ~ ~
28*5225e6b1SAndroid Build Coastguard Worker //! | Command line | (Can also be below the X+10000 mark)
29*5225e6b1SAndroid Build Coastguard Worker //! +------------------------+
30*5225e6b1SAndroid Build Coastguard Worker //! | Stack/heap | For use by the kernel real-mode code.
31*5225e6b1SAndroid Build Coastguard Worker //! low_mem_addr+08000 +------------------------+
32*5225e6b1SAndroid Build Coastguard Worker //! | Kernel setup | The kernel real-mode code.
33*5225e6b1SAndroid Build Coastguard Worker //! | Kernel boot sector | The kernel legacy boot sector.
34*5225e6b1SAndroid Build Coastguard Worker //! low_mem_addr +------------------------+
35*5225e6b1SAndroid Build Coastguard Worker //! | Boot loader | <- Boot sector entry point 0000:7C00
36*5225e6b1SAndroid Build Coastguard Worker //! 001000 +------------------------+
37*5225e6b1SAndroid Build Coastguard Worker //! | Reserved for MBR/BIOS |
38*5225e6b1SAndroid Build Coastguard Worker //! 000800 +------------------------+
39*5225e6b1SAndroid Build Coastguard Worker //! | Typically used by MBR |
40*5225e6b1SAndroid Build Coastguard Worker //! 000600 +------------------------+
41*5225e6b1SAndroid Build Coastguard Worker //! | BIOS use only |
42*5225e6b1SAndroid Build Coastguard Worker //! 000000 +------------------------+
43*5225e6b1SAndroid Build Coastguard Worker //!
44*5225e6b1SAndroid Build Coastguard Worker //! See https://www.kernel.org/doc/html/v5.11/x86/boot.html#the-linux-x86-boot-protocol for more
45*5225e6b1SAndroid Build Coastguard Worker //! detail.
46*5225e6b1SAndroid Build Coastguard Worker
47*5225e6b1SAndroid Build Coastguard Worker use core::arch::asm;
48*5225e6b1SAndroid Build Coastguard Worker use core::mem::size_of;
49*5225e6b1SAndroid Build Coastguard Worker use core::slice::from_raw_parts_mut;
50*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result};
51*5225e6b1SAndroid Build Coastguard Worker use zbi::ZbiContainer;
52*5225e6b1SAndroid Build Coastguard Worker
53*5225e6b1SAndroid Build Coastguard Worker pub use x86_bootparam_defs::{boot_params, e820entry, setup_header};
54*5225e6b1SAndroid Build Coastguard Worker use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref};
55*5225e6b1SAndroid Build Coastguard Worker
56*5225e6b1SAndroid Build Coastguard Worker // Sector size is fixed to 512
57*5225e6b1SAndroid Build Coastguard Worker const SECTOR_SIZE: usize = 512;
58*5225e6b1SAndroid Build Coastguard Worker /// Boot sector and setup code section is 32K at most.
59*5225e6b1SAndroid Build Coastguard Worker const BOOT_SETUP_LOAD_SIZE: usize = 0x8000;
60*5225e6b1SAndroid Build Coastguard Worker /// Address for loading the protected mode kernel
61*5225e6b1SAndroid Build Coastguard Worker const LOAD_ADDR_HIGH: usize = 0x10_0000;
62*5225e6b1SAndroid Build Coastguard Worker // Flag value to use high address for protected mode kernel.
63*5225e6b1SAndroid Build Coastguard Worker const LOAD_FLAG_LOADED_HIGH: u8 = 0x1;
64*5225e6b1SAndroid Build Coastguard Worker
65*5225e6b1SAndroid Build Coastguard Worker /// E820 RAM address range type.
66*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_RAM: u32 = 1;
67*5225e6b1SAndroid Build Coastguard Worker /// E820 reserved address range type.
68*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_RESERVED: u32 = 2;
69*5225e6b1SAndroid Build Coastguard Worker /// E820 ACPI address range type.
70*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_ACPI: u32 = 3;
71*5225e6b1SAndroid Build Coastguard Worker /// E820 NVS address range type.
72*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_NVS: u32 = 4;
73*5225e6b1SAndroid Build Coastguard Worker /// E820 unusable address range type.
74*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_UNUSABLE: u32 = 5;
75*5225e6b1SAndroid Build Coastguard Worker /// E820 PMEM address range type.
76*5225e6b1SAndroid Build Coastguard Worker pub const E820_ADDRESS_TYPE_PMEM: u32 = 7;
77*5225e6b1SAndroid Build Coastguard Worker
78*5225e6b1SAndroid Build Coastguard Worker /// Wrapper for `struct boot_params {}` C structure
79*5225e6b1SAndroid Build Coastguard Worker #[repr(transparent)]
80*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes)]
81*5225e6b1SAndroid Build Coastguard Worker pub struct BootParams(boot_params);
82*5225e6b1SAndroid Build Coastguard Worker
83*5225e6b1SAndroid Build Coastguard Worker impl BootParams {
84*5225e6b1SAndroid Build Coastguard Worker /// Cast a bytes into a reference of BootParams header
from_bytes_ref(buffer: &[u8]) -> Result<&BootParams>85*5225e6b1SAndroid Build Coastguard Worker pub fn from_bytes_ref(buffer: &[u8]) -> Result<&BootParams> {
86*5225e6b1SAndroid Build Coastguard Worker Ok(Ref::<_, BootParams>::new_from_prefix(buffer)
87*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::BufferTooSmall(Some(size_of::<BootParams>())))?
88*5225e6b1SAndroid Build Coastguard Worker .0
89*5225e6b1SAndroid Build Coastguard Worker .into_ref())
90*5225e6b1SAndroid Build Coastguard Worker }
91*5225e6b1SAndroid Build Coastguard Worker
92*5225e6b1SAndroid Build Coastguard Worker /// Cast a bytes into a mutable reference of BootParams header.
from_bytes_mut(buffer: &mut [u8]) -> Result<&mut BootParams>93*5225e6b1SAndroid Build Coastguard Worker pub fn from_bytes_mut(buffer: &mut [u8]) -> Result<&mut BootParams> {
94*5225e6b1SAndroid Build Coastguard Worker Ok(Ref::<_, BootParams>::new_from_prefix(buffer)
95*5225e6b1SAndroid Build Coastguard Worker .ok_or(Error::BufferTooSmall(Some(size_of::<BootParams>())))?
96*5225e6b1SAndroid Build Coastguard Worker .0
97*5225e6b1SAndroid Build Coastguard Worker .into_mut())
98*5225e6b1SAndroid Build Coastguard Worker }
99*5225e6b1SAndroid Build Coastguard Worker
100*5225e6b1SAndroid Build Coastguard Worker /// Return a mutable reference of the `setup_header` struct field in `boot_params`
setup_header_mut(&mut self) -> &mut setup_header101*5225e6b1SAndroid Build Coastguard Worker pub fn setup_header_mut(&mut self) -> &mut setup_header {
102*5225e6b1SAndroid Build Coastguard Worker &mut self.0.hdr
103*5225e6b1SAndroid Build Coastguard Worker }
104*5225e6b1SAndroid Build Coastguard Worker
105*5225e6b1SAndroid Build Coastguard Worker /// Return a const reference of the `setup_header` struct field in `boot_params`
setup_header_ref(&self) -> &setup_header106*5225e6b1SAndroid Build Coastguard Worker pub fn setup_header_ref(&self) -> &setup_header {
107*5225e6b1SAndroid Build Coastguard Worker &self.0.hdr
108*5225e6b1SAndroid Build Coastguard Worker }
109*5225e6b1SAndroid Build Coastguard Worker
110*5225e6b1SAndroid Build Coastguard Worker /// Checks whether image is valid and version is supported.
check(&self) -> Result<()>111*5225e6b1SAndroid Build Coastguard Worker pub fn check(&self) -> Result<()> {
112*5225e6b1SAndroid Build Coastguard Worker // Check magic.
113*5225e6b1SAndroid Build Coastguard Worker if !(self.setup_header_ref().boot_flag == 0xAA55
114*5225e6b1SAndroid Build Coastguard Worker && self.setup_header_ref().header.to_le_bytes() == *b"HdrS")
115*5225e6b1SAndroid Build Coastguard Worker {
116*5225e6b1SAndroid Build Coastguard Worker return Err(Error::BadMagic);
117*5225e6b1SAndroid Build Coastguard Worker }
118*5225e6b1SAndroid Build Coastguard Worker
119*5225e6b1SAndroid Build Coastguard Worker // Check if it is bzimage and version is supported.
120*5225e6b1SAndroid Build Coastguard Worker if !(self.0.hdr.version >= 0x0206
121*5225e6b1SAndroid Build Coastguard Worker && ((self.setup_header_ref().loadflags & LOAD_FLAG_LOADED_HIGH) != 0))
122*5225e6b1SAndroid Build Coastguard Worker {
123*5225e6b1SAndroid Build Coastguard Worker return Err(Error::UnsupportedVersion);
124*5225e6b1SAndroid Build Coastguard Worker }
125*5225e6b1SAndroid Build Coastguard Worker
126*5225e6b1SAndroid Build Coastguard Worker Ok(())
127*5225e6b1SAndroid Build Coastguard Worker }
128*5225e6b1SAndroid Build Coastguard Worker
129*5225e6b1SAndroid Build Coastguard Worker /// Gets the number of sectors in the setup code section.
setup_sects(&self) -> usize130*5225e6b1SAndroid Build Coastguard Worker pub fn setup_sects(&self) -> usize {
131*5225e6b1SAndroid Build Coastguard Worker match self.setup_header_ref().setup_sects {
132*5225e6b1SAndroid Build Coastguard Worker 0 => 4,
133*5225e6b1SAndroid Build Coastguard Worker v => v as usize,
134*5225e6b1SAndroid Build Coastguard Worker }
135*5225e6b1SAndroid Build Coastguard Worker }
136*5225e6b1SAndroid Build Coastguard Worker
137*5225e6b1SAndroid Build Coastguard Worker /// Gets the offset to the protected mode kernel in the image.
138*5225e6b1SAndroid Build Coastguard Worker ///
139*5225e6b1SAndroid Build Coastguard Worker /// The value is also the same as the sum of legacy boot sector plus setup code size.
kernel_off(&self) -> usize140*5225e6b1SAndroid Build Coastguard Worker pub fn kernel_off(&self) -> usize {
141*5225e6b1SAndroid Build Coastguard Worker // one boot sector + setup sectors
142*5225e6b1SAndroid Build Coastguard Worker (1 + self.setup_sects()) * SECTOR_SIZE
143*5225e6b1SAndroid Build Coastguard Worker }
144*5225e6b1SAndroid Build Coastguard Worker
145*5225e6b1SAndroid Build Coastguard Worker /// Gets e820 map entries.
e820_map(&mut self) -> &mut [e820entry]146*5225e6b1SAndroid Build Coastguard Worker pub fn e820_map(&mut self) -> &mut [e820entry] {
147*5225e6b1SAndroid Build Coastguard Worker &mut self.0.e820_map[..]
148*5225e6b1SAndroid Build Coastguard Worker }
149*5225e6b1SAndroid Build Coastguard Worker }
150*5225e6b1SAndroid Build Coastguard Worker
151*5225e6b1SAndroid Build Coastguard Worker /// Boots a Linux bzimage.
152*5225e6b1SAndroid Build Coastguard Worker ///
153*5225e6b1SAndroid Build Coastguard Worker /// # Args
154*5225e6b1SAndroid Build Coastguard Worker ///
155*5225e6b1SAndroid Build Coastguard Worker /// * `kernel`: Buffer holding the loaded bzimage.
156*5225e6b1SAndroid Build Coastguard Worker ///
157*5225e6b1SAndroid Build Coastguard Worker /// * `ramdisk`: Buffer holding the loaded ramdisk.
158*5225e6b1SAndroid Build Coastguard Worker ///
159*5225e6b1SAndroid Build Coastguard Worker /// * `cmdline`: Command line argument blob.
160*5225e6b1SAndroid Build Coastguard Worker ///
161*5225e6b1SAndroid Build Coastguard Worker /// * `mmap_cb`: A caller provided callback for setting the e820 memory map. The callback takes in
162*5225e6b1SAndroid Build Coastguard Worker /// a mutable reference of e820 map entries (&mut [e820entry]). On success, it should return
163*5225e6b1SAndroid Build Coastguard Worker /// the number of used entries. On error, it can return a
164*5225e6b1SAndroid Build Coastguard Worker /// `Error::MemoryMapCallbackError(<code>)` to propagate a custom error code.
165*5225e6b1SAndroid Build Coastguard Worker ///
166*5225e6b1SAndroid Build Coastguard Worker /// * `low_mem_addr`: The lowest memory touched by the bootloader section. This is where boot param
167*5225e6b1SAndroid Build Coastguard Worker /// starts.
168*5225e6b1SAndroid Build Coastguard Worker ///
169*5225e6b1SAndroid Build Coastguard Worker /// * The API is not expected to return on success.
170*5225e6b1SAndroid Build Coastguard Worker ///
171*5225e6b1SAndroid Build Coastguard Worker /// # Safety
172*5225e6b1SAndroid Build Coastguard Worker ///
173*5225e6b1SAndroid Build Coastguard Worker /// * Caller must ensure that `kernel` contains a valid Linux kernel and `low_mem_addr` is valid
174*5225e6b1SAndroid Build Coastguard Worker ///
175*5225e6b1SAndroid Build Coastguard Worker /// * Caller must ensure that there is enough memory at address 0x10_0000 for relocating `kernel`.
boot_linux_bzimage<F>( kernel: &[u8], ramdisk: &[u8], cmdline: &[u8], mmap_cb: F, low_mem_addr: usize, ) -> Result<()> where F: FnOnce(&mut [e820entry]) -> Result<u8>,176*5225e6b1SAndroid Build Coastguard Worker pub unsafe fn boot_linux_bzimage<F>(
177*5225e6b1SAndroid Build Coastguard Worker kernel: &[u8],
178*5225e6b1SAndroid Build Coastguard Worker ramdisk: &[u8],
179*5225e6b1SAndroid Build Coastguard Worker cmdline: &[u8],
180*5225e6b1SAndroid Build Coastguard Worker mmap_cb: F,
181*5225e6b1SAndroid Build Coastguard Worker low_mem_addr: usize,
182*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()>
183*5225e6b1SAndroid Build Coastguard Worker where
184*5225e6b1SAndroid Build Coastguard Worker F: FnOnce(&mut [e820entry]) -> Result<u8>,
185*5225e6b1SAndroid Build Coastguard Worker {
186*5225e6b1SAndroid Build Coastguard Worker let bootparam = BootParams::from_bytes_ref(&kernel[..])?;
187*5225e6b1SAndroid Build Coastguard Worker bootparam.check()?;
188*5225e6b1SAndroid Build Coastguard Worker
189*5225e6b1SAndroid Build Coastguard Worker // low memory address greater than 0x9_0000 is bogus.
190*5225e6b1SAndroid Build Coastguard Worker assert!(low_mem_addr <= 0x9_0000);
191*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, `low_mem_addr` points to sufficiently large
192*5225e6b1SAndroid Build Coastguard Worker // memory.
193*5225e6b1SAndroid Build Coastguard Worker let boot_param_buffer =
194*5225e6b1SAndroid Build Coastguard Worker unsafe { from_raw_parts_mut(low_mem_addr as *mut _, BOOT_SETUP_LOAD_SIZE) };
195*5225e6b1SAndroid Build Coastguard Worker // Note: We currently boot directly from protected mode kernel and bypass real-mode kernel.
196*5225e6b1SAndroid Build Coastguard Worker // Thus we omit the heap section. Revisit this if we encounter platforms that have to boot from
197*5225e6b1SAndroid Build Coastguard Worker // real-mode kernel.
198*5225e6b1SAndroid Build Coastguard Worker let cmdline_start = low_mem_addr + BOOT_SETUP_LOAD_SIZE;
199*5225e6b1SAndroid Build Coastguard Worker // Should not reach into I/O memory hole section.
200*5225e6b1SAndroid Build Coastguard Worker assert!(cmdline_start + cmdline.len() <= 0x0A0000);
201*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, `low_mem_addr` points to sufficiently large
202*5225e6b1SAndroid Build Coastguard Worker // memory.
203*5225e6b1SAndroid Build Coastguard Worker let cmdline_buffer = unsafe { from_raw_parts_mut(cmdline_start as *mut _, cmdline.len()) };
204*5225e6b1SAndroid Build Coastguard Worker
205*5225e6b1SAndroid Build Coastguard Worker let boot_sector_size = bootparam.kernel_off();
206*5225e6b1SAndroid Build Coastguard Worker // Copy protected mode kernel to load address
207*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, `LOAD_ADDR_HIGH` points to sufficiently
208*5225e6b1SAndroid Build Coastguard Worker // large memory.
209*5225e6b1SAndroid Build Coastguard Worker unsafe {
210*5225e6b1SAndroid Build Coastguard Worker from_raw_parts_mut(LOAD_ADDR_HIGH as *mut u8, kernel[boot_sector_size..].len())
211*5225e6b1SAndroid Build Coastguard Worker .clone_from_slice(&kernel[boot_sector_size..]);
212*5225e6b1SAndroid Build Coastguard Worker }
213*5225e6b1SAndroid Build Coastguard Worker
214*5225e6b1SAndroid Build Coastguard Worker // Zeroizes the entire boot sector.
215*5225e6b1SAndroid Build Coastguard Worker boot_param_buffer.fill(0);
216*5225e6b1SAndroid Build Coastguard Worker let bootparam_fixup = BootParams::from_bytes_mut(boot_param_buffer)?;
217*5225e6b1SAndroid Build Coastguard Worker // Only copies over the header. Leaves the rest zeroes.
218*5225e6b1SAndroid Build Coastguard Worker *bootparam_fixup.setup_header_mut() =
219*5225e6b1SAndroid Build Coastguard Worker *BootParams::from_bytes_ref(&kernel[..])?.setup_header_ref();
220*5225e6b1SAndroid Build Coastguard Worker
221*5225e6b1SAndroid Build Coastguard Worker let bootparam_fixup = BootParams::from_bytes_mut(boot_param_buffer)?;
222*5225e6b1SAndroid Build Coastguard Worker
223*5225e6b1SAndroid Build Coastguard Worker // Sets commandline.
224*5225e6b1SAndroid Build Coastguard Worker cmdline_buffer.clone_from_slice(cmdline);
225*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.setup_header_mut().cmd_line_ptr = cmdline_start.try_into().unwrap();
226*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.setup_header_mut().cmdline_size = cmdline.len().try_into().unwrap();
227*5225e6b1SAndroid Build Coastguard Worker
228*5225e6b1SAndroid Build Coastguard Worker // Sets ramdisk address.
229*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.setup_header_mut().ramdisk_image = (ramdisk.as_ptr() as usize).try_into()?;
230*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.setup_header_mut().ramdisk_size = ramdisk.len().try_into()?;
231*5225e6b1SAndroid Build Coastguard Worker
232*5225e6b1SAndroid Build Coastguard Worker // Sets to loader type "special loader". (Anything other than 0, otherwise linux kernel ignores
233*5225e6b1SAndroid Build Coastguard Worker // ramdisk.)
234*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.setup_header_mut().type_of_loader = 0xff;
235*5225e6b1SAndroid Build Coastguard Worker
236*5225e6b1SAndroid Build Coastguard Worker // Fix up e820 memory map.
237*5225e6b1SAndroid Build Coastguard Worker let num_entries = mmap_cb(bootparam_fixup.e820_map())?;
238*5225e6b1SAndroid Build Coastguard Worker bootparam_fixup.0.e820_entries = num_entries;
239*5225e6b1SAndroid Build Coastguard Worker
240*5225e6b1SAndroid Build Coastguard Worker // Clears stack pointers, interrupt and jumps to protected mode kernel.
241*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, input contains a valid linux kernel.
242*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
243*5225e6b1SAndroid Build Coastguard Worker unsafe {
244*5225e6b1SAndroid Build Coastguard Worker asm!(
245*5225e6b1SAndroid Build Coastguard Worker "xor ebp, ebp",
246*5225e6b1SAndroid Build Coastguard Worker "xor esp, esp",
247*5225e6b1SAndroid Build Coastguard Worker "cld",
248*5225e6b1SAndroid Build Coastguard Worker "cli",
249*5225e6b1SAndroid Build Coastguard Worker "jmp {ep}",
250*5225e6b1SAndroid Build Coastguard Worker ep = in(reg) LOAD_ADDR_HIGH,
251*5225e6b1SAndroid Build Coastguard Worker in("rsi") low_mem_addr,
252*5225e6b1SAndroid Build Coastguard Worker );
253*5225e6b1SAndroid Build Coastguard Worker }
254*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, input contains a valid linux kernel.
255*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "x86")]
256*5225e6b1SAndroid Build Coastguard Worker unsafe {
257*5225e6b1SAndroid Build Coastguard Worker asm!(
258*5225e6b1SAndroid Build Coastguard Worker "xor ebp, ebp",
259*5225e6b1SAndroid Build Coastguard Worker "xor esp, esp",
260*5225e6b1SAndroid Build Coastguard Worker "mov esi, eax",
261*5225e6b1SAndroid Build Coastguard Worker "cld",
262*5225e6b1SAndroid Build Coastguard Worker "cli",
263*5225e6b1SAndroid Build Coastguard Worker "jmp {ep}",
264*5225e6b1SAndroid Build Coastguard Worker ep = in(reg) LOAD_ADDR_HIGH,
265*5225e6b1SAndroid Build Coastguard Worker in("eax") low_mem_addr,
266*5225e6b1SAndroid Build Coastguard Worker );
267*5225e6b1SAndroid Build Coastguard Worker }
268*5225e6b1SAndroid Build Coastguard Worker
269*5225e6b1SAndroid Build Coastguard Worker Ok(())
270*5225e6b1SAndroid Build Coastguard Worker }
271*5225e6b1SAndroid Build Coastguard Worker
272*5225e6b1SAndroid Build Coastguard Worker /// Jump to prepared ZBI Fuchsia entry
273*5225e6b1SAndroid Build Coastguard Worker ///
274*5225e6b1SAndroid Build Coastguard Worker /// SAFETY:
275*5225e6b1SAndroid Build Coastguard Worker /// Caller must ensure `entry` is valid entry point for kernel.
276*5225e6b1SAndroid Build Coastguard Worker /// Caller must ensure `data` is valid ZBI data and is 4K aligned.
zbi_boot_raw(entry: usize, data: &[u8]) -> !277*5225e6b1SAndroid Build Coastguard Worker pub unsafe fn zbi_boot_raw(entry: usize, data: &[u8]) -> ! {
278*5225e6b1SAndroid Build Coastguard Worker // Clears stack pointers, interrupt and jumps to protected mode kernel.
279*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, input contains a valid ZBI kernel.
280*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
281*5225e6b1SAndroid Build Coastguard Worker unsafe {
282*5225e6b1SAndroid Build Coastguard Worker asm!(
283*5225e6b1SAndroid Build Coastguard Worker "xor ebp, ebp",
284*5225e6b1SAndroid Build Coastguard Worker "xor esp, esp",
285*5225e6b1SAndroid Build Coastguard Worker "cld",
286*5225e6b1SAndroid Build Coastguard Worker "cli",
287*5225e6b1SAndroid Build Coastguard Worker "jmp {ep}",
288*5225e6b1SAndroid Build Coastguard Worker ep = in(reg) entry,
289*5225e6b1SAndroid Build Coastguard Worker in("rsi") data.as_ptr(),
290*5225e6b1SAndroid Build Coastguard Worker );
291*5225e6b1SAndroid Build Coastguard Worker }
292*5225e6b1SAndroid Build Coastguard Worker // SAFETY: By safety requirement of this function, input contains a valid ZBI kernel.
293*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "x86")]
294*5225e6b1SAndroid Build Coastguard Worker unsafe {
295*5225e6b1SAndroid Build Coastguard Worker asm!(
296*5225e6b1SAndroid Build Coastguard Worker "xor ebp, ebp",
297*5225e6b1SAndroid Build Coastguard Worker "xor esp, esp",
298*5225e6b1SAndroid Build Coastguard Worker "mov esi, eax",
299*5225e6b1SAndroid Build Coastguard Worker "cld",
300*5225e6b1SAndroid Build Coastguard Worker "cli",
301*5225e6b1SAndroid Build Coastguard Worker "jmp {ep}",
302*5225e6b1SAndroid Build Coastguard Worker ep = in(reg) entry,
303*5225e6b1SAndroid Build Coastguard Worker in("eax") data.as_ptr(),
304*5225e6b1SAndroid Build Coastguard Worker );
305*5225e6b1SAndroid Build Coastguard Worker }
306*5225e6b1SAndroid Build Coastguard Worker
307*5225e6b1SAndroid Build Coastguard Worker unreachable!();
308*5225e6b1SAndroid Build Coastguard Worker }
309*5225e6b1SAndroid Build Coastguard Worker
310*5225e6b1SAndroid Build Coastguard Worker /// Boot ZBI kernel from provided ZBI containers
311*5225e6b1SAndroid Build Coastguard Worker ///
312*5225e6b1SAndroid Build Coastguard Worker /// SAFETY:
313*5225e6b1SAndroid Build Coastguard Worker /// Caller must ensure `kernel` is valid ZBI kernel and is 4K aligned.
314*5225e6b1SAndroid Build Coastguard Worker /// Caller must ensure `data` is valid ZBI data and is 4K aligned.
zbi_boot(kernel: &[u8], data: &[u8]) -> !315*5225e6b1SAndroid Build Coastguard Worker pub unsafe fn zbi_boot(kernel: &[u8], data: &[u8]) -> ! {
316*5225e6b1SAndroid Build Coastguard Worker let (entry, _) =
317*5225e6b1SAndroid Build Coastguard Worker ZbiContainer::parse(kernel).unwrap().get_kernel_entry_and_reserved_memory_size().unwrap();
318*5225e6b1SAndroid Build Coastguard Worker let addr = (kernel.as_ptr() as usize).checked_add(usize::try_from(entry).unwrap()).unwrap();
319*5225e6b1SAndroid Build Coastguard Worker // SAFETY:
320*5225e6b1SAndroid Build Coastguard Worker // `addr` is calculated from kernel ZBI, which is valid according to safety requirements for
321*5225e6b1SAndroid Build Coastguard Worker // `zbi_boot()` function.
322*5225e6b1SAndroid Build Coastguard Worker // `data` is required to be valid ZBI data as per safety requirements for `zbi_boot()`
323*5225e6b1SAndroid Build Coastguard Worker unsafe { zbi_boot_raw(addr, data) };
324*5225e6b1SAndroid Build Coastguard Worker }
325