blob: e3ade23c49a5225830aa54b091de05d9ec9110ce [file]
// Copyright 2023, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{efi_blocks::find_block_devices, fastboot::fastboot, ops::Ops};
use efi::{exit_boot_services, EfiEntry};
use libgbl::{android_boot::load_android_simple, gbl_print, gbl_println, GblOps, Result};
// The following implements a demo for booting Android from disk. It can be run from
// Cuttlefish by adding `--android_efi_loader=<path of this EFI binary>` to the command line.
//
// A number of simplifications are made (see `android_load::load_android_simple()`):
//
// * No A/B slot switching is performed. It always boot from *_a slot.
// * No AVB is performed.
// * No dynamic partitions.
// * Only support V3/V4 image and Android 13+ (generic ramdisk from the "init_boot" partition)
//
// The missing pieces above are currently under development as part of the full end-to-end boot
// flow in libgbl, which will eventually replace this demo. The demo is currently used as an
// end-to-end test for libraries developed so far.
pub fn android_boot_demo(entry: EfiEntry) -> Result<()> {
let mut blks = find_block_devices(&entry)?;
let partitions = &blks.as_gbl_parts()?;
let mut ops = Ops { efi_entry: &entry, partitions };
match ops.should_stop_in_fastboot() {
Ok(true) => {
fastboot(&mut ops)?;
}
Ok(false) => {}
Err(e) => {
gbl_println!(ops, "Warning: error while checking fastboot trigger ({:?})", e);
gbl_println!(ops, "Ignoring error and continuing with normal boot");
}
}
gbl_println!(ops, "Try booting as Android");
// Allocate buffer for load.
let mut load_buffer = vec![0u8; 128 * 1024 * 1024]; // 128MB
let (ramdisk, fdt, kernel, remains) = load_android_simple(&mut ops, &mut load_buffer[..])?;
gbl_println!(ops, "");
gbl_println!(
ops,
"Booting kernel @ {:#x}, ramdisk @ {:#x}, fdt @ {:#x}",
kernel.as_ptr() as usize,
ramdisk.as_ptr() as usize,
fdt.as_ptr() as usize
);
gbl_println!(ops, "");
#[cfg(target_arch = "aarch64")]
{
drop(blks); // Drop `blks` to release the borrow on `entry`.
let _ = exit_boot_services(entry, remains)?;
// SAFETY: We currently targets at Cuttlefish emulator where images are provided valid.
unsafe { boot::aarch64::jump_linux_el2_or_lower(kernel, ramdisk, fdt) };
}
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
{
use fdt::Fdt;
use liberror::Error;
use libgbl::android_boot::BOOTARGS_PROP;
let fdt = Fdt::new(&fdt[..])?;
drop(blks); // Drop `blks` to release the borrow on `entry`.
let efi_mmap = exit_boot_services(entry, remains)?;
// SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
unsafe {
boot::x86::boot_linux_bzimage(
kernel,
ramdisk,
fdt.get_property("chosen", BOOTARGS_PROP).unwrap(),
|e820_entries| {
// Convert EFI memory type to e820 memory type.
if efi_mmap.len() > e820_entries.len() {
return Err(Error::MemoryMapCallbackError(-1));
}
for (idx, mem) in efi_mmap.into_iter().enumerate() {
e820_entries[idx] = boot::x86::e820entry {
addr: mem.physical_start,
size: mem.number_of_pages * 4096,
type_: crate::utils::efi_to_e820_mem_type(mem.memory_type),
};
}
Ok(efi_mmap.len().try_into().unwrap())
},
0x9_0000,
)?;
}
unreachable!();
}
#[cfg(target_arch = "riscv64")]
{
let boot_hart_id = entry
.system_table()
.boot_services()
.find_first_and_open::<efi::protocol::riscv::RiscvBootProtocol>()?
.get_boot_hartid()?;
gbl_println!(ops, "riscv boot_hart_id: {}", boot_hart_id);
drop(blks); // Drop `blks` to release the borrow on `entry`.
let _ = exit_boot_services(entry, remains)?;
// SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
unsafe { boot::riscv64::jump_linux(kernel, boot_hart_id, fdt) };
}
}