xref: /aosp_15_r20/bootable/libbootloader/gbl/efi/src/utils.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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;
16*5225e6b1SAndroid Build Coastguard Worker use ::efi::EfiMemoryAttributesTable;
17*5225e6b1SAndroid Build Coastguard Worker use efi::{
18*5225e6b1SAndroid Build Coastguard Worker     protocol::{
19*5225e6b1SAndroid Build Coastguard Worker         device_path::{DevicePathProtocol, DevicePathText, DevicePathToTextProtocol},
20*5225e6b1SAndroid Build Coastguard Worker         loaded_image::LoadedImageProtocol,
21*5225e6b1SAndroid Build Coastguard Worker         simple_text_input::SimpleTextInputProtocol,
22*5225e6b1SAndroid Build Coastguard Worker     },
23*5225e6b1SAndroid Build Coastguard Worker     utils::Timeout,
24*5225e6b1SAndroid Build Coastguard Worker     DeviceHandle, EfiEntry,
25*5225e6b1SAndroid Build Coastguard Worker };
26*5225e6b1SAndroid Build Coastguard Worker use efi_types::{EfiGuid, EfiInputKey};
27*5225e6b1SAndroid Build Coastguard Worker use fdt::FdtHeader;
28*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
29*5225e6b1SAndroid Build Coastguard Worker use libgbl::Result;
30*5225e6b1SAndroid Build Coastguard Worker 
31*5225e6b1SAndroid Build Coastguard Worker pub const EFI_DTB_TABLE_GUID: EfiGuid =
32*5225e6b1SAndroid Build Coastguard Worker     EfiGuid::new(0xb1b621d5, 0xf19c, 0x41a5, [0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]);
33*5225e6b1SAndroid Build Coastguard Worker 
34*5225e6b1SAndroid Build Coastguard Worker /// Helper function to get the `DevicePathText` from a `DeviceHandle`.
get_device_path<'a>( entry: &'a EfiEntry, handle: DeviceHandle, ) -> Result<DevicePathText<'a>>35*5225e6b1SAndroid Build Coastguard Worker pub fn get_device_path<'a>(
36*5225e6b1SAndroid Build Coastguard Worker     entry: &'a EfiEntry,
37*5225e6b1SAndroid Build Coastguard Worker     handle: DeviceHandle,
38*5225e6b1SAndroid Build Coastguard Worker ) -> Result<DevicePathText<'a>> {
39*5225e6b1SAndroid Build Coastguard Worker     let bs = entry.system_table().boot_services();
40*5225e6b1SAndroid Build Coastguard Worker     let path = bs.open_protocol::<DevicePathProtocol>(handle)?;
41*5225e6b1SAndroid Build Coastguard Worker     let path_to_text = bs.find_first_and_open::<DevicePathToTextProtocol>()?;
42*5225e6b1SAndroid Build Coastguard Worker     Ok(path_to_text.convert_device_path_to_text(&path, false, false)?)
43*5225e6b1SAndroid Build Coastguard Worker }
44*5225e6b1SAndroid Build Coastguard Worker 
45*5225e6b1SAndroid Build Coastguard Worker /// Helper function to get the loaded image path.
loaded_image_path(entry: &EfiEntry) -> Result<DevicePathText>46*5225e6b1SAndroid Build Coastguard Worker pub fn loaded_image_path(entry: &EfiEntry) -> Result<DevicePathText> {
47*5225e6b1SAndroid Build Coastguard Worker     get_device_path(
48*5225e6b1SAndroid Build Coastguard Worker         entry,
49*5225e6b1SAndroid Build Coastguard Worker         entry
50*5225e6b1SAndroid Build Coastguard Worker             .system_table()
51*5225e6b1SAndroid Build Coastguard Worker             .boot_services()
52*5225e6b1SAndroid Build Coastguard Worker             .open_protocol::<LoadedImageProtocol>(entry.image_handle())?
53*5225e6b1SAndroid Build Coastguard Worker             .device_handle()?,
54*5225e6b1SAndroid Build Coastguard Worker     )
55*5225e6b1SAndroid Build Coastguard Worker }
56*5225e6b1SAndroid Build Coastguard Worker 
57*5225e6b1SAndroid Build Coastguard Worker /// Find FDT from EFI configuration table.
get_efi_fdt<'a>(entry: &'a EfiEntry) -> Option<(&FdtHeader, &[u8])>58*5225e6b1SAndroid Build Coastguard Worker pub fn get_efi_fdt<'a>(entry: &'a EfiEntry) -> Option<(&FdtHeader, &[u8])> {
59*5225e6b1SAndroid Build Coastguard Worker     if let Some(config_tables) = entry.system_table().configuration_table() {
60*5225e6b1SAndroid Build Coastguard Worker         for table in config_tables {
61*5225e6b1SAndroid Build Coastguard Worker             if table.vendor_guid == EFI_DTB_TABLE_GUID {
62*5225e6b1SAndroid Build Coastguard Worker                 // SAFETY: Buffer provided by EFI configuration table.
63*5225e6b1SAndroid Build Coastguard Worker                 return unsafe { FdtHeader::from_raw(table.vendor_table as *const _).ok() };
64*5225e6b1SAndroid Build Coastguard Worker             }
65*5225e6b1SAndroid Build Coastguard Worker         }
66*5225e6b1SAndroid Build Coastguard Worker     }
67*5225e6b1SAndroid Build Coastguard Worker     None
68*5225e6b1SAndroid Build Coastguard Worker }
69*5225e6b1SAndroid Build Coastguard Worker 
70*5225e6b1SAndroid Build Coastguard Worker #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
efi_to_e820_mem_type(efi_mem_type: u32) -> u3271*5225e6b1SAndroid Build Coastguard Worker pub fn efi_to_e820_mem_type(efi_mem_type: u32) -> u32 {
72*5225e6b1SAndroid Build Coastguard Worker     match efi_mem_type {
73*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_LOADER_CODE
74*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_LOADER_DATA
75*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_BOOT_SERVICES_CODE
76*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_BOOT_SERVICES_DATA
77*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_CONVENTIONAL_MEMORY => boot::x86::E820_ADDRESS_TYPE_RAM,
78*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_RUNTIME_SERVICES_CODE
79*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_RUNTIME_SERVICES_DATA
80*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_MEMORY_MAPPED_IO
81*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_MEMORY_MAPPED_IOPORT_SPACE
82*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_PAL_CODE
83*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_RESERVED_MEMORY_TYPE => boot::x86::E820_ADDRESS_TYPE_RESERVED,
84*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_UNUSABLE_MEMORY => boot::x86::E820_ADDRESS_TYPE_UNUSABLE,
85*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_ACPIRECLAIM_MEMORY => boot::x86::E820_ADDRESS_TYPE_ACPI,
86*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_ACPIMEMORY_NVS => boot::x86::E820_ADDRESS_TYPE_NVS,
87*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_PERSISTENT_MEMORY => boot::x86::E820_ADDRESS_TYPE_PMEM,
88*5225e6b1SAndroid Build Coastguard Worker         v => panic!("Unmapped EFI memory type {v}"),
89*5225e6b1SAndroid Build Coastguard Worker     }
90*5225e6b1SAndroid Build Coastguard Worker }
91*5225e6b1SAndroid Build Coastguard Worker 
92*5225e6b1SAndroid Build Coastguard Worker /// Repetitively runs a closure until it signals completion or timeout.
93*5225e6b1SAndroid Build Coastguard Worker ///
94*5225e6b1SAndroid Build Coastguard Worker /// * If `f` returns `Ok(R)`, an `Ok(Some(R))` is returned immediately.
95*5225e6b1SAndroid Build Coastguard Worker /// * If `f` has been repetitively called and returning `Err(false)` for `timeout_ms`,  an
96*5225e6b1SAndroid Build Coastguard Worker ///   `Ok(None)` is returned. This is the time out case.
97*5225e6b1SAndroid Build Coastguard Worker /// * If `f` returns `Err(true)` the timeout is reset.
loop_with_timeout<F, R>(efi_entry: &EfiEntry, timeout_ms: u64, mut f: F) -> Result<Option<R>> where F: FnMut() -> core::result::Result<R, bool>,98*5225e6b1SAndroid Build Coastguard Worker pub fn loop_with_timeout<F, R>(efi_entry: &EfiEntry, timeout_ms: u64, mut f: F) -> Result<Option<R>>
99*5225e6b1SAndroid Build Coastguard Worker where
100*5225e6b1SAndroid Build Coastguard Worker     F: FnMut() -> core::result::Result<R, bool>,
101*5225e6b1SAndroid Build Coastguard Worker {
102*5225e6b1SAndroid Build Coastguard Worker     let timeout = Timeout::new(efi_entry, timeout_ms)?;
103*5225e6b1SAndroid Build Coastguard Worker     while !timeout.check()? {
104*5225e6b1SAndroid Build Coastguard Worker         match f() {
105*5225e6b1SAndroid Build Coastguard Worker             Ok(v) => return Ok(Some(v)),
106*5225e6b1SAndroid Build Coastguard Worker             Err(true) => timeout.reset(timeout_ms)?,
107*5225e6b1SAndroid Build Coastguard Worker             _ => {}
108*5225e6b1SAndroid Build Coastguard Worker         }
109*5225e6b1SAndroid Build Coastguard Worker     }
110*5225e6b1SAndroid Build Coastguard Worker     Ok(None)
111*5225e6b1SAndroid Build Coastguard Worker }
112*5225e6b1SAndroid Build Coastguard Worker 
113*5225e6b1SAndroid Build Coastguard Worker /// Waits for a key stroke value from simple text input.
114*5225e6b1SAndroid Build Coastguard Worker ///
115*5225e6b1SAndroid Build Coastguard Worker /// Returns `Ok(true)` if the expected key stroke is read, `Ok(false)` if timeout, `Err` otherwise.
wait_key_stroke( efi_entry: &EfiEntry, pred: impl Fn(EfiInputKey) -> bool, timeout_ms: u64, ) -> Result<bool>116*5225e6b1SAndroid Build Coastguard Worker pub fn wait_key_stroke(
117*5225e6b1SAndroid Build Coastguard Worker     efi_entry: &EfiEntry,
118*5225e6b1SAndroid Build Coastguard Worker     pred: impl Fn(EfiInputKey) -> bool,
119*5225e6b1SAndroid Build Coastguard Worker     timeout_ms: u64,
120*5225e6b1SAndroid Build Coastguard Worker ) -> Result<bool> {
121*5225e6b1SAndroid Build Coastguard Worker     let input = efi_entry
122*5225e6b1SAndroid Build Coastguard Worker         .system_table()
123*5225e6b1SAndroid Build Coastguard Worker         .boot_services()
124*5225e6b1SAndroid Build Coastguard Worker         .find_first_and_open::<SimpleTextInputProtocol>()?;
125*5225e6b1SAndroid Build Coastguard Worker     loop_with_timeout(efi_entry, timeout_ms, || -> core::result::Result<Result<bool>, bool> {
126*5225e6b1SAndroid Build Coastguard Worker         match input.read_key_stroke() {
127*5225e6b1SAndroid Build Coastguard Worker             Ok(Some(key)) if pred(key) => Ok(Ok(true)),
128*5225e6b1SAndroid Build Coastguard Worker             Err(e) => Ok(Err(e.into())),
129*5225e6b1SAndroid Build Coastguard Worker             _ => Err(false),
130*5225e6b1SAndroid Build Coastguard Worker         }
131*5225e6b1SAndroid Build Coastguard Worker     })?
132*5225e6b1SAndroid Build Coastguard Worker     .unwrap_or(Ok(false))
133*5225e6b1SAndroid Build Coastguard Worker }
134*5225e6b1SAndroid Build Coastguard Worker 
135*5225e6b1SAndroid Build Coastguard Worker // Converts an EFI memory type to a zbi_mem_range_t type.
efi_to_zbi_mem_range_type(efi_mem_type: u32) -> u32136*5225e6b1SAndroid Build Coastguard Worker pub fn efi_to_zbi_mem_range_type(efi_mem_type: u32) -> u32 {
137*5225e6b1SAndroid Build Coastguard Worker     match efi_mem_type {
138*5225e6b1SAndroid Build Coastguard Worker         efi_types::EFI_MEMORY_TYPE_LOADER_CODE
139*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_LOADER_DATA
140*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_BOOT_SERVICES_CODE
141*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_BOOT_SERVICES_DATA
142*5225e6b1SAndroid Build Coastguard Worker         | efi_types::EFI_MEMORY_TYPE_CONVENTIONAL_MEMORY => zbi::zbi_format::ZBI_MEM_TYPE_RAM,
143*5225e6b1SAndroid Build Coastguard Worker         _ => zbi::zbi_format::ZBI_MEM_TYPE_RESERVED,
144*5225e6b1SAndroid Build Coastguard Worker     }
145*5225e6b1SAndroid Build Coastguard Worker }
146*5225e6b1SAndroid Build Coastguard Worker 
147*5225e6b1SAndroid Build Coastguard Worker /// Find Memory attributes from EFI configuration_table
148*5225e6b1SAndroid Build Coastguard Worker #[allow(unused)]
get_efi_mem_attr<'a>(entry: &'a EfiEntry) -> Option<EfiMemoryAttributesTable<'static>>149*5225e6b1SAndroid Build Coastguard Worker pub fn get_efi_mem_attr<'a>(entry: &'a EfiEntry) -> Option<EfiMemoryAttributesTable<'static>> {
150*5225e6b1SAndroid Build Coastguard Worker     entry.system_table().configuration_table().and_then(|config_tables| {
151*5225e6b1SAndroid Build Coastguard Worker         config_tables
152*5225e6b1SAndroid Build Coastguard Worker             .iter()
153*5225e6b1SAndroid Build Coastguard Worker             .find_map(|&table| {
154*5225e6b1SAndroid Build Coastguard Worker                 // SAFETY:
155*5225e6b1SAndroid Build Coastguard Worker                 // `table` is valid EFI Configuration table provided by EFI
156*5225e6b1SAndroid Build Coastguard Worker                 match unsafe { EfiMemoryAttributesTable::new(table) } {
157*5225e6b1SAndroid Build Coastguard Worker                     Err(Error::NotFound) => None,
158*5225e6b1SAndroid Build Coastguard Worker                     other => Some(other.ok()),
159*5225e6b1SAndroid Build Coastguard Worker                 }
160*5225e6b1SAndroid Build Coastguard Worker             })
161*5225e6b1SAndroid Build Coastguard Worker             .flatten()
162*5225e6b1SAndroid Build Coastguard Worker     })
163*5225e6b1SAndroid Build Coastguard Worker }
164