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 use crate::{efi_blocks::find_block_devices, fastboot::fastboot, ops::Ops, ops::RambootOps};
16*5225e6b1SAndroid Build Coastguard Worker use efi::{exit_boot_services, EfiEntry};
17*5225e6b1SAndroid Build Coastguard Worker use libgbl::{android_boot::load_android_simple, gbl_print, gbl_println, GblOps, Os, Result};
18*5225e6b1SAndroid Build Coastguard Worker
19*5225e6b1SAndroid Build Coastguard Worker // The following implements a demo for booting Android from disk. It can be run from
20*5225e6b1SAndroid Build Coastguard Worker // Cuttlefish by adding `--android_efi_loader=<path of this EFI binary>` to the command line.
21*5225e6b1SAndroid Build Coastguard Worker //
22*5225e6b1SAndroid Build Coastguard Worker // A number of simplifications are made (see `android_load::load_android_simple()`):
23*5225e6b1SAndroid Build Coastguard Worker //
24*5225e6b1SAndroid Build Coastguard Worker // * No A/B slot switching is performed. It always boot from *_a slot.
25*5225e6b1SAndroid Build Coastguard Worker // * No AVB is performed.
26*5225e6b1SAndroid Build Coastguard Worker // * No dynamic partitions.
27*5225e6b1SAndroid Build Coastguard Worker // * Only support V3/V4 image and Android 13+ (generic ramdisk from the "init_boot" partition)
28*5225e6b1SAndroid Build Coastguard Worker //
29*5225e6b1SAndroid Build Coastguard Worker // The missing pieces above are currently under development as part of the full end-to-end boot
30*5225e6b1SAndroid Build Coastguard Worker // flow in libgbl, which will eventually replace this demo. The demo is currently used as an
31*5225e6b1SAndroid Build Coastguard Worker // end-to-end test for libraries developed so far.
android_boot_demo(entry: EfiEntry) -> Result<()>32*5225e6b1SAndroid Build Coastguard Worker pub fn android_boot_demo(entry: EfiEntry) -> Result<()> {
33*5225e6b1SAndroid Build Coastguard Worker let blks = find_block_devices(&entry)?;
34*5225e6b1SAndroid Build Coastguard Worker let mut ops = Ops::new(&entry, &blks[..], Some(Os::Android));
35*5225e6b1SAndroid Build Coastguard Worker let mut bootimg_buffer = &mut vec![0u8; 128 * 1024 * 1024][..]; // 128 MB
36*5225e6b1SAndroid Build Coastguard Worker
37*5225e6b1SAndroid Build Coastguard Worker match ops.should_stop_in_fastboot() {
38*5225e6b1SAndroid Build Coastguard Worker Ok(true) => fastboot(&mut ops, &mut bootimg_buffer)?,
39*5225e6b1SAndroid Build Coastguard Worker Err(e) => {
40*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "Warning: error while checking fastboot trigger ({:?})", e);
41*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "Ignoring error and continuing with normal boot");
42*5225e6b1SAndroid Build Coastguard Worker }
43*5225e6b1SAndroid Build Coastguard Worker _ => {}
44*5225e6b1SAndroid Build Coastguard Worker }
45*5225e6b1SAndroid Build Coastguard Worker
46*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "Try booting as Android");
47*5225e6b1SAndroid Build Coastguard Worker
48*5225e6b1SAndroid Build Coastguard Worker // Allocate buffer for load.
49*5225e6b1SAndroid Build Coastguard Worker let mut load_buffer = vec![0u8; 128 * 1024 * 1024]; // 128MB
50*5225e6b1SAndroid Build Coastguard Worker
51*5225e6b1SAndroid Build Coastguard Worker let (ramdisk, fdt, kernel, remains) = if bootimg_buffer.starts_with(b"ANDROID!") {
52*5225e6b1SAndroid Build Coastguard Worker let mut ramboot_ops = RambootOps { ops: &mut ops, bootimg_buffer };
53*5225e6b1SAndroid Build Coastguard Worker load_android_simple(&mut ramboot_ops, &mut load_buffer[..])?
54*5225e6b1SAndroid Build Coastguard Worker } else {
55*5225e6b1SAndroid Build Coastguard Worker load_android_simple(&mut ops, &mut load_buffer[..])?
56*5225e6b1SAndroid Build Coastguard Worker };
57*5225e6b1SAndroid Build Coastguard Worker
58*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "");
59*5225e6b1SAndroid Build Coastguard Worker gbl_println!(
60*5225e6b1SAndroid Build Coastguard Worker ops,
61*5225e6b1SAndroid Build Coastguard Worker "Booting kernel @ {:#x}, ramdisk @ {:#x}, fdt @ {:#x}",
62*5225e6b1SAndroid Build Coastguard Worker kernel.as_ptr() as usize,
63*5225e6b1SAndroid Build Coastguard Worker ramdisk.as_ptr() as usize,
64*5225e6b1SAndroid Build Coastguard Worker fdt.as_ptr() as usize
65*5225e6b1SAndroid Build Coastguard Worker );
66*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "");
67*5225e6b1SAndroid Build Coastguard Worker
68*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "aarch64")]
69*5225e6b1SAndroid Build Coastguard Worker {
70*5225e6b1SAndroid Build Coastguard Worker drop(blks); // Drop `blks` to release the borrow on `entry`.
71*5225e6b1SAndroid Build Coastguard Worker let _ = exit_boot_services(entry, remains)?;
72*5225e6b1SAndroid Build Coastguard Worker // SAFETY: We currently targets at Cuttlefish emulator where images are provided valid.
73*5225e6b1SAndroid Build Coastguard Worker unsafe { boot::aarch64::jump_linux_el2_or_lower(kernel, ramdisk, fdt) };
74*5225e6b1SAndroid Build Coastguard Worker }
75*5225e6b1SAndroid Build Coastguard Worker
76*5225e6b1SAndroid Build Coastguard Worker #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
77*5225e6b1SAndroid Build Coastguard Worker {
78*5225e6b1SAndroid Build Coastguard Worker use fdt::Fdt;
79*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
80*5225e6b1SAndroid Build Coastguard Worker use libgbl::android_boot::BOOTARGS_PROP;
81*5225e6b1SAndroid Build Coastguard Worker
82*5225e6b1SAndroid Build Coastguard Worker let fdt = Fdt::new(&fdt[..])?;
83*5225e6b1SAndroid Build Coastguard Worker drop(blks); // Drop `blks` to release the borrow on `entry`.
84*5225e6b1SAndroid Build Coastguard Worker let efi_mmap = exit_boot_services(entry, remains)?;
85*5225e6b1SAndroid Build Coastguard Worker // SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
86*5225e6b1SAndroid Build Coastguard Worker unsafe {
87*5225e6b1SAndroid Build Coastguard Worker boot::x86::boot_linux_bzimage(
88*5225e6b1SAndroid Build Coastguard Worker kernel,
89*5225e6b1SAndroid Build Coastguard Worker ramdisk,
90*5225e6b1SAndroid Build Coastguard Worker fdt.get_property("chosen", BOOTARGS_PROP).unwrap(),
91*5225e6b1SAndroid Build Coastguard Worker |e820_entries| {
92*5225e6b1SAndroid Build Coastguard Worker // Convert EFI memory type to e820 memory type.
93*5225e6b1SAndroid Build Coastguard Worker if efi_mmap.len() > e820_entries.len() {
94*5225e6b1SAndroid Build Coastguard Worker return Err(Error::MemoryMapCallbackError(-1));
95*5225e6b1SAndroid Build Coastguard Worker }
96*5225e6b1SAndroid Build Coastguard Worker for (idx, mem) in efi_mmap.into_iter().enumerate() {
97*5225e6b1SAndroid Build Coastguard Worker e820_entries[idx] = boot::x86::e820entry {
98*5225e6b1SAndroid Build Coastguard Worker addr: mem.physical_start,
99*5225e6b1SAndroid Build Coastguard Worker size: mem.number_of_pages * 4096,
100*5225e6b1SAndroid Build Coastguard Worker type_: crate::utils::efi_to_e820_mem_type(mem.memory_type),
101*5225e6b1SAndroid Build Coastguard Worker };
102*5225e6b1SAndroid Build Coastguard Worker }
103*5225e6b1SAndroid Build Coastguard Worker Ok(efi_mmap.len().try_into().unwrap())
104*5225e6b1SAndroid Build Coastguard Worker },
105*5225e6b1SAndroid Build Coastguard Worker 0x9_0000,
106*5225e6b1SAndroid Build Coastguard Worker )?;
107*5225e6b1SAndroid Build Coastguard Worker }
108*5225e6b1SAndroid Build Coastguard Worker unreachable!();
109*5225e6b1SAndroid Build Coastguard Worker }
110*5225e6b1SAndroid Build Coastguard Worker
111*5225e6b1SAndroid Build Coastguard Worker #[cfg(target_arch = "riscv64")]
112*5225e6b1SAndroid Build Coastguard Worker {
113*5225e6b1SAndroid Build Coastguard Worker let boot_hart_id = entry
114*5225e6b1SAndroid Build Coastguard Worker .system_table()
115*5225e6b1SAndroid Build Coastguard Worker .boot_services()
116*5225e6b1SAndroid Build Coastguard Worker .find_first_and_open::<efi::protocol::riscv::RiscvBootProtocol>()?
117*5225e6b1SAndroid Build Coastguard Worker .get_boot_hartid()?;
118*5225e6b1SAndroid Build Coastguard Worker gbl_println!(ops, "riscv boot_hart_id: {}", boot_hart_id);
119*5225e6b1SAndroid Build Coastguard Worker drop(blks); // Drop `blks` to release the borrow on `entry`.
120*5225e6b1SAndroid Build Coastguard Worker let _ = exit_boot_services(entry, remains)?;
121*5225e6b1SAndroid Build Coastguard Worker // SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
122*5225e6b1SAndroid Build Coastguard Worker unsafe { boot::riscv64::jump_linux(kernel, boot_hart_id, fdt) };
123*5225e6b1SAndroid Build Coastguard Worker }
124*5225e6b1SAndroid Build Coastguard Worker }
125