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