xref: /aosp_15_r20/bootable/libbootloader/gbl/libefi/src/protocol.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 //! 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