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 core::ptr::null_mut; 16 17 use crate::defs::*; 18 use crate::{DeviceHandle, EfiEntry, EfiResult}; 19 20 pub mod android_boot; 21 pub mod block_io; 22 pub mod device_path; 23 pub mod loaded_image; 24 pub mod riscv; 25 pub mod simple_network; 26 pub mod simple_text_input; 27 pub mod simple_text_output; 28 29 /// ProtocolInfo provides GUID info and the EFI data structure type for a protocol. 30 pub trait ProtocolInfo { 31 /// Data structure type of the interface. 32 type InterfaceType; 33 /// GUID of the protocol. 34 const GUID: EfiGuid; 35 } 36 37 /// A generic type for representing an EFI protcol. 38 pub struct Protocol<'a, T: ProtocolInfo> { 39 // The handle to the device offering the protocol. It's needed for closing the protocol. 40 device: DeviceHandle, 41 // The interface protocol itself. 42 interface: *mut T::InterfaceType, 43 // The `EfiEntry` data 44 efi_entry: &'a EfiEntry, 45 } 46 47 /// A base implementation for Protocol<T>. 48 /// Protocol<T> will have additional implementation based on type `T`. 49 impl<'a, T: ProtocolInfo> Protocol<'a, T> { 50 /// Create a new instance with the given device handle, interface pointer and `EfiEntry` data. 51 /// 52 /// # Safety 53 /// 54 /// Caller needs to ensure that 55 /// 56 /// * `interface` points to a valid object of type T::InterfaceType. 57 /// 58 /// * 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, ) -> Self59 pub(crate) unsafe fn new( 60 device: DeviceHandle, 61 interface: *mut T::InterfaceType, 62 efi_entry: &'a EfiEntry, 63 ) -> Self { 64 Self { device, interface, efi_entry } 65 } 66 67 /// Returns the EFI data structure for the protocol interface. interface(&self) -> EfiResult<&T::InterfaceType>68 pub fn interface(&self) -> EfiResult<&T::InterfaceType> { 69 // SAFETY: EFI protocol interface data structure. 70 unsafe { self.interface.as_ref() }.ok_or_else(|| EFI_STATUS_INVALID_PARAMETER.into()) 71 } 72 73 /// Returns the reference to EFI entry. efi_entry(&self) -> &'a EfiEntry74 pub fn efi_entry(&self) -> &'a EfiEntry { 75 self.efi_entry 76 } 77 78 /// Returns the mutable pointer of the interface. Invisible from outside. Application should 79 /// not have any need to alter the content of interface data. interface_ptr(&self) -> *mut T::InterfaceType80 pub(crate) fn interface_ptr(&self) -> *mut T::InterfaceType { 81 self.interface 82 } 83 } 84 85 impl<T: ProtocolInfo> Drop for Protocol<'_, T> { drop(&mut self)86 fn drop(&mut self) { 87 // If the device handle is not specified when creating the Protocol<T>, treat the 88 // handle as a static permanent reference and don't close it. An example is 89 // `EFI_SYSTEM_TABLE.ConOut`. 90 if self.device.0 != null_mut() { 91 self.efi_entry.system_table().boot_services().close_protocol::<T>(self.device).unwrap(); 92 } 93 } 94 } 95 96 impl EfiGuid { new(data1: u32, data2: u16, data3: u16, data4: [u8; 8usize]) -> Self97 pub const fn new(data1: u32, data2: u16, data3: u16, data4: [u8; 8usize]) -> Self { 98 EfiGuid { data1, data2, data3, data4 } 99 } 100 } 101 102 #[macro_export] 103 macro_rules! efi_call { 104 ( $method:expr, $($x:expr),*$(,)? ) => { 105 { 106 let res: EfiResult<()> = match $method { 107 None => Err(EFI_STATUS_NOT_FOUND.into()), 108 Some(f) => map_efi_err(f($($x,)*)) 109 }; 110 res 111 } 112 }; 113 } 114 115 // Following are protocol specific implementations for Protocol<T>. 116 // TODO(300168989): Consdier splitting each protocol into separate file as we add more protocols. 117 118 #[cfg(test)] 119 mod test { 120 use super::*; 121 use crate::test::*; 122 123 #[test] test_dont_close_protocol_without_device_handle()124 fn test_dont_close_protocol_without_device_handle() { 125 run_test(|image_handle, systab_ptr| { 126 let efi_entry = EfiEntry { image_handle, systab_ptr }; 127 let mut block_io: EfiBlockIoProtocol = Default::default(); 128 // SAFETY: `block_io` is a EfiBlockIoProtocol and out lives the created Protocol. 129 unsafe { 130 Protocol::<block_io::BlockIoProtocol>::new( 131 DeviceHandle(null_mut()), 132 &mut block_io as *mut _, 133 &efi_entry, 134 ); 135 } 136 efi_call_traces().with(|traces| { 137 assert_eq!(traces.borrow_mut().close_protocol_trace.inputs.len(), 0); 138 }); 139 }) 140 } 141 } 142