• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::{
16     fastboot::{with_fastboot_channels, VecPinFut},
17     ops::Ops,
18     utils::{get_platform_buffer_info, BufferInfo},
19 };
20 use alloc::{boxed::Box, vec::Vec};
21 use core::{fmt::Write, str::from_utf8};
22 use efi::{efi_print, efi_println, exit_boot_services, EfiEntry};
23 use efi_types::{GBL_IMAGE_TYPE_FASTBOOT, GBL_IMAGE_TYPE_OS_LOAD};
24 use gbl_async::poll;
25 use libgbl::{android_boot::android_main, gbl_print, gbl_println, GblOps, Result};
26 
27 const SZ_MB: usize = 1024 * 1024;
28 
29 /// Android bootloader main entry (before booting).
30 ///
31 /// On success, returns a tuple of slices (ramdisk, fdt, kernel, remains).
efi_android_load( ops: &mut Ops, ) -> Result<(&'static mut [u8], &'static mut [u8], &'static mut [u8], &'static mut [u8])>32 pub fn efi_android_load(
33     ops: &mut Ops,
34 ) -> Result<(&'static mut [u8], &'static mut [u8], &'static mut [u8], &'static mut [u8])> {
35     let entry = ops.efi_entry;
36     // Prepares the OS load buffer.
37     let img_type_os_load = from_utf8(GBL_IMAGE_TYPE_OS_LOAD).unwrap();
38     let load_buffer = match get_platform_buffer_info(&entry, img_type_os_load, 256 * SZ_MB) {
39         BufferInfo::Static(v) => v,
40         BufferInfo::Alloc(sz) => {
41             let alloc = vec![0u8; sz];
42             gbl_println!(ops, "Allocated {:#x} bytes for OS load buffer.", alloc.len());
43             alloc.leak()
44         }
45     };
46 
47     // Checks if we have a reserved buffer for fastboot
48     let img_type_fastboot = from_utf8(GBL_IMAGE_TYPE_FASTBOOT).unwrap();
49     let mut fastboot_buffer_info = None;
50 
51     gbl_println!(ops, "Try booting as Android");
52 
53     Ok(android_main(ops, load_buffer.as_mut(), |fb| {
54         // Note: `get_or_insert_with` lazily evaluates closure (only when insert is necessary).
55         let buffer = fastboot_buffer_info.get_or_insert_with(|| {
56             get_platform_buffer_info(&entry, img_type_fastboot, 512 * SZ_MB)
57         });
58         let mut alloc;
59         let buffer = match buffer {
60             BufferInfo::Static(v) => &mut v[..],
61             BufferInfo::Alloc(sz) => {
62                 alloc = vec![0u8; *sz];
63                 efi_println!(entry, "Allocated {:#x} bytes for fastboot buffer.", alloc.len());
64                 &mut alloc
65             }
66         };
67         // TODO(b/383620444): Investigate letting GblOps return fastboot channels.
68         with_fastboot_channels(&entry, |local, usb, tcp| {
69             // We currently only consider 1 parallell flash + 1 parallel download.
70             // This can be made configurable if necessary.
71             const GBL_FB_N: usize = 2;
72             let mut bufs = Vec::from_iter(buffer.chunks_exact_mut(buffer.len() / GBL_FB_N));
73             let bufs = &(&mut bufs[..]).into();
74             let mut fut = Box::pin(fb.run(bufs, VecPinFut::default(), local, usb, tcp));
75             while poll(&mut fut).is_none() {}
76         })
77     })?)
78 }
79 
80 /// Exits boot services and boots loaded android images.
efi_android_boot( entry: EfiEntry, kernel: &[u8], ramdisk: &[u8], fdt: &[u8], remains: &mut [u8], ) -> Result<()>81 pub fn efi_android_boot(
82     entry: EfiEntry,
83     kernel: &[u8],
84     ramdisk: &[u8],
85     fdt: &[u8],
86     remains: &mut [u8],
87 ) -> Result<()> {
88     efi_println!(entry, "");
89     efi_println!(
90         entry,
91         "Booting kernel @ {:#x}, ramdisk @ {:#x}, fdt @ {:#x}",
92         kernel.as_ptr() as usize,
93         ramdisk.as_ptr() as usize,
94         fdt.as_ptr() as usize
95     );
96     efi_println!(entry, "");
97 
98     #[cfg(target_arch = "aarch64")]
99     {
100         let _ = exit_boot_services(entry, remains)?;
101         // SAFETY: We currently targets at Cuttlefish emulator where images are provided valid.
102         unsafe { boot::aarch64::jump_linux_el2_or_lower(kernel, ramdisk, fdt) };
103     }
104 
105     #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
106     {
107         use fdt::Fdt;
108         use liberror::Error;
109         use libgbl::android_boot::BOOTARGS_PROP;
110 
111         let fdt = Fdt::new(&fdt[..])?;
112         let efi_mmap = exit_boot_services(entry, remains)?;
113         // SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
114         unsafe {
115             boot::x86::boot_linux_bzimage(
116                 kernel,
117                 ramdisk,
118                 fdt.get_property("chosen", BOOTARGS_PROP).unwrap(),
119                 |e820_entries| {
120                     // Convert EFI memory type to e820 memory type.
121                     if efi_mmap.len() > e820_entries.len() {
122                         return Err(Error::MemoryMapCallbackError(-1));
123                     }
124                     for (idx, mem) in efi_mmap.into_iter().enumerate() {
125                         e820_entries[idx] = boot::x86::e820entry {
126                             addr: mem.physical_start,
127                             size: mem.number_of_pages * 4096,
128                             type_: crate::utils::efi_to_e820_mem_type(mem.memory_type),
129                         };
130                     }
131                     Ok(efi_mmap.len().try_into().unwrap())
132                 },
133                 0x9_0000,
134             )?;
135         }
136         unreachable!();
137     }
138 
139     #[cfg(target_arch = "riscv64")]
140     {
141         let boot_hart_id = entry
142             .system_table()
143             .boot_services()
144             .find_first_and_open::<efi::protocol::riscv::RiscvBootProtocol>()?
145             .get_boot_hartid()?;
146         efi_println!(entry, "riscv boot_hart_id: {}", boot_hart_id);
147         let _ = exit_boot_services(entry, remains)?;
148         // SAFETY: We currently target at Cuttlefish emulator where images are provided valid.
149         unsafe { boot::riscv64::jump_linux(kernel, boot_hart_id, fdt) };
150     }
151 }
152