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 //! EFI protocol wrappers to provide Rust-safe APIs for usage. 16*5225e6b1SAndroid Build Coastguard Worker 17*5225e6b1SAndroid Build Coastguard Worker use core::ptr::null_mut; 18*5225e6b1SAndroid Build Coastguard Worker 19*5225e6b1SAndroid Build Coastguard Worker use crate::{DeviceHandle, EfiEntry}; 20*5225e6b1SAndroid Build Coastguard Worker use efi_types::*; 21*5225e6b1SAndroid Build Coastguard Worker 22*5225e6b1SAndroid Build Coastguard Worker pub mod block_io; 23*5225e6b1SAndroid Build Coastguard Worker pub mod block_io2; 24*5225e6b1SAndroid Build Coastguard Worker pub mod device_path; 25*5225e6b1SAndroid Build Coastguard Worker pub mod dt_fixup; 26*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_ab_slot; 27*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_avb; 28*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_fastboot; 29*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_fastboot_usb; 30*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_image_loading; 31*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_efi_os_configuration; 32*5225e6b1SAndroid Build Coastguard Worker pub mod loaded_image; 33*5225e6b1SAndroid Build Coastguard Worker pub mod riscv; 34*5225e6b1SAndroid Build Coastguard Worker pub mod simple_network; 35*5225e6b1SAndroid Build Coastguard Worker pub mod simple_text_input; 36*5225e6b1SAndroid Build Coastguard Worker pub mod simple_text_output; 37*5225e6b1SAndroid Build Coastguard Worker 38*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result}; 39*5225e6b1SAndroid Build Coastguard Worker 40*5225e6b1SAndroid Build Coastguard Worker /// ProtocolInfo provides GUID info and the EFI data structure type for a protocol. 41*5225e6b1SAndroid Build Coastguard Worker pub trait ProtocolInfo { 42*5225e6b1SAndroid Build Coastguard Worker /// Data structure type of the interface. 43*5225e6b1SAndroid Build Coastguard Worker type InterfaceType; 44*5225e6b1SAndroid Build Coastguard Worker /// GUID of the protocol. 45*5225e6b1SAndroid Build Coastguard Worker const GUID: EfiGuid; 46*5225e6b1SAndroid Build Coastguard Worker } 47*5225e6b1SAndroid Build Coastguard Worker 48*5225e6b1SAndroid Build Coastguard Worker /// A generic type for representing an EFI protcol. 49*5225e6b1SAndroid Build Coastguard Worker pub struct Protocol<'a, T: ProtocolInfo> { 50*5225e6b1SAndroid Build Coastguard Worker // The handle to the device offering the protocol. It's needed for closing the protocol. 51*5225e6b1SAndroid Build Coastguard Worker device: DeviceHandle, 52*5225e6b1SAndroid Build Coastguard Worker // The interface protocol itself. 53*5225e6b1SAndroid Build Coastguard Worker interface: *mut T::InterfaceType, 54*5225e6b1SAndroid Build Coastguard Worker // The `EfiEntry` data 55*5225e6b1SAndroid Build Coastguard Worker efi_entry: &'a EfiEntry, 56*5225e6b1SAndroid Build Coastguard Worker } 57*5225e6b1SAndroid Build Coastguard Worker 58*5225e6b1SAndroid Build Coastguard Worker /// A base implementation for Protocol<T>. 59*5225e6b1SAndroid Build Coastguard Worker /// Protocol<T> will have additional implementation based on type `T`. 60*5225e6b1SAndroid Build Coastguard Worker impl<'a, T: ProtocolInfo> Protocol<'a, T> { 61*5225e6b1SAndroid Build Coastguard Worker /// Create a new instance with the given device handle, interface pointer and `EfiEntry` data. 62*5225e6b1SAndroid Build Coastguard Worker /// 63*5225e6b1SAndroid Build Coastguard Worker /// # Safety 64*5225e6b1SAndroid Build Coastguard Worker /// 65*5225e6b1SAndroid Build Coastguard Worker /// Caller needs to ensure that 66*5225e6b1SAndroid Build Coastguard Worker /// 67*5225e6b1SAndroid Build Coastguard Worker /// * `interface` points to a valid object of type T::InterfaceType. 68*5225e6b1SAndroid Build Coastguard Worker /// 69*5225e6b1SAndroid Build Coastguard Worker /// * Object pointed to by `interface` must live as long as the create `Protocol` or 'a. new( device: DeviceHandle, interface: *mut T::InterfaceType, efi_entry: &'a EfiEntry, ) -> Self70*5225e6b1SAndroid Build Coastguard Worker pub(crate) unsafe fn new( 71*5225e6b1SAndroid Build Coastguard Worker device: DeviceHandle, 72*5225e6b1SAndroid Build Coastguard Worker interface: *mut T::InterfaceType, 73*5225e6b1SAndroid Build Coastguard Worker efi_entry: &'a EfiEntry, 74*5225e6b1SAndroid Build Coastguard Worker ) -> Self { 75*5225e6b1SAndroid Build Coastguard Worker Self { device, interface, efi_entry } 76*5225e6b1SAndroid Build Coastguard Worker } 77*5225e6b1SAndroid Build Coastguard Worker 78*5225e6b1SAndroid Build Coastguard Worker /// Returns the EFI data structure for the protocol interface. interface(&self) -> Result<&T::InterfaceType>79*5225e6b1SAndroid Build Coastguard Worker pub fn interface(&self) -> Result<&T::InterfaceType> { 80*5225e6b1SAndroid Build Coastguard Worker // SAFETY: EFI protocol interface data structure. 81*5225e6b1SAndroid Build Coastguard Worker unsafe { self.interface.as_ref() }.ok_or(Error::InvalidInput) 82*5225e6b1SAndroid Build Coastguard Worker } 83*5225e6b1SAndroid Build Coastguard Worker 84*5225e6b1SAndroid Build Coastguard Worker /// Returns the reference to EFI entry. efi_entry(&self) -> &'a EfiEntry85*5225e6b1SAndroid Build Coastguard Worker pub fn efi_entry(&self) -> &'a EfiEntry { 86*5225e6b1SAndroid Build Coastguard Worker self.efi_entry 87*5225e6b1SAndroid Build Coastguard Worker } 88*5225e6b1SAndroid Build Coastguard Worker 89*5225e6b1SAndroid Build Coastguard Worker /// Returns the mutable pointer of the interface. Invisible from outside. Application should 90*5225e6b1SAndroid Build Coastguard Worker /// not have any need to alter the content of interface data. interface_ptr(&self) -> *mut T::InterfaceType91*5225e6b1SAndroid Build Coastguard Worker pub(crate) fn interface_ptr(&self) -> *mut T::InterfaceType { 92*5225e6b1SAndroid Build Coastguard Worker self.interface 93*5225e6b1SAndroid Build Coastguard Worker } 94*5225e6b1SAndroid Build Coastguard Worker } 95*5225e6b1SAndroid Build Coastguard Worker 96*5225e6b1SAndroid Build Coastguard Worker impl<T: ProtocolInfo> Drop for Protocol<'_, T> { drop(&mut self)97*5225e6b1SAndroid Build Coastguard Worker fn drop(&mut self) { 98*5225e6b1SAndroid Build Coastguard Worker // If the device handle is not specified when creating the Protocol<T>, treat the 99*5225e6b1SAndroid Build Coastguard Worker // handle as a static permanent reference and don't close it. An example is 100*5225e6b1SAndroid Build Coastguard Worker // `EFI_SYSTEM_TABLE.ConOut`. 101*5225e6b1SAndroid Build Coastguard Worker if self.device.0 != null_mut() { 102*5225e6b1SAndroid Build Coastguard Worker // Currently we open all protocols using flags BY_HANDLE_PROTOCOL. The flag allows a 103*5225e6b1SAndroid Build Coastguard Worker // protocol to be opened for multiple copies, which is needed if a UEFI protocol 104*5225e6b1SAndroid Build Coastguard Worker // implementation also require access for other protocols. But if any one of them is 105*5225e6b1SAndroid Build Coastguard Worker // closed, all other opened copies will be affected. Therefore for now we don't close 106*5225e6b1SAndroid Build Coastguard Worker // the protocol on drop. In the future when we start using other flags such as 107*5225e6b1SAndroid Build Coastguard Worker // EXCLUSIVE, we should perform protocol close based on the open flags. 108*5225e6b1SAndroid Build Coastguard Worker 109*5225e6b1SAndroid Build Coastguard Worker // self.efi_entry.system_table().boot_services().close_protocol::<T>(self.device).unwrap(); 110*5225e6b1SAndroid Build Coastguard Worker } 111*5225e6b1SAndroid Build Coastguard Worker } 112*5225e6b1SAndroid Build Coastguard Worker } 113*5225e6b1SAndroid Build Coastguard Worker 114*5225e6b1SAndroid Build Coastguard Worker /// Macro to perform an EFI protocol function call. 115*5225e6b1SAndroid Build Coastguard Worker /// 116*5225e6b1SAndroid Build Coastguard Worker /// In the first variant, the first argument is the function pointer, 117*5225e6b1SAndroid Build Coastguard Worker /// and the following arguments are passed through as protocol args. 118*5225e6b1SAndroid Build Coastguard Worker /// 119*5225e6b1SAndroid Build Coastguard Worker /// With our [Protocol] struct, usage generally looks something like: 120*5225e6b1SAndroid Build Coastguard Worker /// 121*5225e6b1SAndroid Build Coastguard Worker /// ``` 122*5225e6b1SAndroid Build Coastguard Worker /// efi_call!( 123*5225e6b1SAndroid Build Coastguard Worker /// self.interface()?.protocol_function_name, 124*5225e6b1SAndroid Build Coastguard Worker /// self.interface, 125*5225e6b1SAndroid Build Coastguard Worker /// arg1, 126*5225e6b1SAndroid Build Coastguard Worker /// arg2, 127*5225e6b1SAndroid Build Coastguard Worker /// ... 128*5225e6b1SAndroid Build Coastguard Worker /// ) 129*5225e6b1SAndroid Build Coastguard Worker /// ``` 130*5225e6b1SAndroid Build Coastguard Worker /// Most efi_call! invocations should use the first variant. 131*5225e6b1SAndroid Build Coastguard Worker /// 132*5225e6b1SAndroid Build Coastguard Worker /// With the second variant, the first argument is an expression that references 133*5225e6b1SAndroid Build Coastguard Worker /// a buffer in-out size parameter. 134*5225e6b1SAndroid Build Coastguard Worker /// This is part of a pattern used by some protocol methods 135*5225e6b1SAndroid Build Coastguard Worker /// that take an output buffer and an in-out buffer size: 136*5225e6b1SAndroid Build Coastguard Worker /// if the method returns EFI_STATUS_BUFFER_TOO_SMALL, 137*5225e6b1SAndroid Build Coastguard Worker /// the size is mutated to contain the minimum required buffer size. 138*5225e6b1SAndroid Build Coastguard Worker /// The caller can then allocate a larger buffer and reattempt the method call. 139*5225e6b1SAndroid Build Coastguard Worker /// 140*5225e6b1SAndroid Build Coastguard Worker /// Usage generally looks something like: 141*5225e6b1SAndroid Build Coastguard Worker /// ``` 142*5225e6b1SAndroid Build Coastguard Worker /// efi_call!( 143*5225e6b1SAndroid Build Coastguard Worker /// @bufsize arg2, 144*5225e6b1SAndroid Build Coastguard Worker /// self.interface()?.protocol_function_name, 145*5225e6b1SAndroid Build Coastguard Worker /// self.interface, 146*5225e6b1SAndroid Build Coastguard Worker /// arg1, 147*5225e6b1SAndroid Build Coastguard Worker /// &mut arg2, 148*5225e6b1SAndroid Build Coastguard Worker /// ... 149*5225e6b1SAndroid Build Coastguard Worker /// ) 150*5225e6b1SAndroid Build Coastguard Worker /// ``` 151*5225e6b1SAndroid Build Coastguard Worker #[macro_export] 152*5225e6b1SAndroid Build Coastguard Worker macro_rules! efi_call { 153*5225e6b1SAndroid Build Coastguard Worker ( $method:expr, $($x:expr),*$(,)? ) => { 154*5225e6b1SAndroid Build Coastguard Worker { 155*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result, efi_status_to_result}; 156*5225e6b1SAndroid Build Coastguard Worker let res: Result<()> = match $method { 157*5225e6b1SAndroid Build Coastguard Worker None => Err(Error::NotFound), 158*5225e6b1SAndroid Build Coastguard Worker Some(f) => efi_status_to_result(f($($x,)*)), 159*5225e6b1SAndroid Build Coastguard Worker }; 160*5225e6b1SAndroid Build Coastguard Worker res 161*5225e6b1SAndroid Build Coastguard Worker } 162*5225e6b1SAndroid Build Coastguard Worker }; 163*5225e6b1SAndroid Build Coastguard Worker ( @bufsize $size:expr, $method:expr, $($x:expr),*$(,)? ) => { 164*5225e6b1SAndroid Build Coastguard Worker { 165*5225e6b1SAndroid Build Coastguard Worker use liberror::{Error, Result, efi_status_to_result}; 166*5225e6b1SAndroid Build Coastguard Worker use efi_types::EFI_STATUS_BUFFER_TOO_SMALL; 167*5225e6b1SAndroid Build Coastguard Worker let res: Result<()> = match $method { 168*5225e6b1SAndroid Build Coastguard Worker None => Err(Error::NotFound), 169*5225e6b1SAndroid Build Coastguard Worker Some(f) => { 170*5225e6b1SAndroid Build Coastguard Worker match f($($x,)*) { 171*5225e6b1SAndroid Build Coastguard Worker EFI_STATUS_BUFFER_TOO_SMALL => Err(Error::BufferTooSmall(Some($size))), 172*5225e6b1SAndroid Build Coastguard Worker r => efi_status_to_result(r), 173*5225e6b1SAndroid Build Coastguard Worker } 174*5225e6b1SAndroid Build Coastguard Worker }, 175*5225e6b1SAndroid Build Coastguard Worker }; 176*5225e6b1SAndroid Build Coastguard Worker res 177*5225e6b1SAndroid Build Coastguard Worker } 178*5225e6b1SAndroid Build Coastguard Worker }; 179*5225e6b1SAndroid Build Coastguard Worker } 180*5225e6b1SAndroid Build Coastguard Worker 181*5225e6b1SAndroid Build Coastguard Worker // Following are protocol specific implementations for Protocol<T>. 182*5225e6b1SAndroid Build Coastguard Worker // TODO(300168989): Consdier splitting each protocol into separate file as we add more protocols. 183*5225e6b1SAndroid Build Coastguard Worker 184*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)] 185*5225e6b1SAndroid Build Coastguard Worker mod test { 186*5225e6b1SAndroid Build Coastguard Worker use super::*; 187*5225e6b1SAndroid Build Coastguard Worker use crate::test::*; 188*5225e6b1SAndroid Build Coastguard Worker 189*5225e6b1SAndroid Build Coastguard Worker #[test] test_dont_close_protocol_without_device_handle()190*5225e6b1SAndroid Build Coastguard Worker fn test_dont_close_protocol_without_device_handle() { 191*5225e6b1SAndroid Build Coastguard Worker run_test(|image_handle, systab_ptr| { 192*5225e6b1SAndroid Build Coastguard Worker let efi_entry = EfiEntry { image_handle, systab_ptr }; 193*5225e6b1SAndroid Build Coastguard Worker let mut block_io: EfiBlockIoProtocol = Default::default(); 194*5225e6b1SAndroid Build Coastguard Worker // SAFETY: `block_io` is a EfiBlockIoProtocol and out lives the created Protocol. 195*5225e6b1SAndroid Build Coastguard Worker unsafe { 196*5225e6b1SAndroid Build Coastguard Worker Protocol::<block_io::BlockIoProtocol>::new( 197*5225e6b1SAndroid Build Coastguard Worker DeviceHandle(null_mut()), 198*5225e6b1SAndroid Build Coastguard Worker &mut block_io as *mut _, 199*5225e6b1SAndroid Build Coastguard Worker &efi_entry, 200*5225e6b1SAndroid Build Coastguard Worker ); 201*5225e6b1SAndroid Build Coastguard Worker } 202*5225e6b1SAndroid Build Coastguard Worker efi_call_traces().with(|traces| { 203*5225e6b1SAndroid Build Coastguard Worker assert_eq!(traces.borrow_mut().close_protocol_trace.inputs.len(), 0); 204*5225e6b1SAndroid Build Coastguard Worker }); 205*5225e6b1SAndroid Build Coastguard Worker }) 206*5225e6b1SAndroid Build Coastguard Worker } 207*5225e6b1SAndroid Build Coastguard Worker } 208