• 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 //! This EFI application implements a demo for booting Android/Fuchsia from disk. See
16 //! bootable/libbootloader/gbl/README.md for how to run the demo. See comments of
17 //! `android_boot:android_boot_demo()` and `fuchsia_boot:fuchsia_boot_demo()` for
18 //! supported/unsupported features at the moment.
19 
20 #![cfg_attr(not(test), no_std)]
21 
22 // For the `vec!` macro
23 #[macro_use]
24 extern crate alloc;
25 
26 mod efi_blocks;
27 mod error;
28 mod ops;
29 #[macro_use]
30 mod utils;
31 
32 // Currently un-testable modules.
33 //
34 // The libefi API surface is large and complex; rather than trying to mock it all out at once, we
35 // will selectively enable modules for test as they become mockable.
36 #[cfg(not(test))]
37 mod android_boot;
38 #[cfg(not(test))]
39 mod fastboot;
40 #[cfg(not(test))]
41 mod fuchsia_boot;
42 #[cfg(not(test))]
43 mod net;
44 
45 // In tests, map the `efi_mocks` module as `efi`. This allows other modules to `use crate::efi`
46 // and automatically pick up the correct one.
47 #[cfg(not(test))]
48 pub(crate) use efi;
49 #[cfg(test)]
50 pub(crate) use efi_mocks as efi;
51 
52 #[cfg(not(test))]
53 use {
54     crate::{
55         efi_blocks::{find_block_devices, EfiGblDisk},
56         ops::Ops,
57     },
58     core::fmt::Write,
59     efi::{efi_print, efi_println, EfiEntry},
60     libgbl::{Os, Result},
61     utils::loaded_image_path,
62 };
63 
64 #[cfg(not(test))]
65 enum TargetOs {
66     Android,
67     Fuchsia,
68 }
69 
70 #[cfg(not(test))]
get_target_os(entry: &EfiEntry, disks: &[EfiGblDisk]) -> TargetOs71 fn get_target_os(entry: &EfiEntry, disks: &[EfiGblDisk]) -> TargetOs {
72     let mut buf = [0u8; 1];
73     if entry
74         .system_table()
75         .runtime_services()
76         .get_variable(&efi::GBL_EFI_VENDOR_GUID, efi::GBL_EFI_OS_BOOT_TARGET_VARNAME, &mut buf)
77         .is_ok()
78     {
79         efi_println!(
80             entry,
81             "`{}` is set. Proceeding as Fuchsia.",
82             efi::GBL_EFI_OS_BOOT_TARGET_VARNAME
83         );
84         TargetOs::Fuchsia
85     } else if fuchsia_boot::is_fuchsia_gpt(disks).is_ok() {
86         efi_println!(entry, "Partition layout looks like Fuchsia. Proceeding as Fuchsia");
87         TargetOs::Fuchsia
88     } else {
89         efi_println!(entry, "Proceeding as Android");
90         TargetOs::Android
91     }
92 }
93 
94 /// GBL EFI application logic entry point.
95 #[cfg(not(test))]
app_main(entry: EfiEntry) -> Result<()>96 pub fn app_main(entry: EfiEntry) -> Result<()> {
97     efi_println!(entry, "****Generic Bootloader Application****");
98     if let Ok(v) = loaded_image_path(&entry) {
99         efi_println!(entry, "Image path: {}", v);
100     }
101 
102     let disks = find_block_devices(&entry)?;
103     match get_target_os(&entry, &disks) {
104         TargetOs::Fuchsia => {
105             let mut ops = Ops::new(&entry, &disks[..], Some(Os::Fuchsia));
106             let (kernel, zbi_items) = fuchsia_boot::efi_fuchsia_load(&mut ops)?;
107             drop(disks);
108             fuchsia_boot::efi_fuchsia_boot(entry, kernel, zbi_items)?;
109         }
110         TargetOs::Android => {
111             let mut ops = Ops::new(&entry, &disks[..], Some(Os::Android));
112             let (ramdisk, fdt, kernel, remains) = android_boot::efi_android_load(&mut ops)?;
113             drop(disks);
114             android_boot::efi_android_boot(entry, kernel, ramdisk, fdt, remains)?;
115         }
116     }
117 
118     Ok(())
119 }
120