1 // Copyright 2024, 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 //! Mock protocols. 16 //! 17 //! The structure of these sub-modules must match the libefi structure so that the code can refer 18 //! to either one using the same path. 19 20 use crate::{DeviceHandle, MOCK_EFI}; 21 use core::ffi::CStr; 22 use core::fmt::Write; 23 pub use efi::protocol::gbl_efi_image_loading::EfiImageBufferInfo; 24 use efi_types::{ 25 EfiInputKey, GblEfiAvbKeyValidationStatus, GblEfiAvbVerificationResult, GblEfiImageInfo, 26 GblEfiPartitionName, GblEfiVerifiedDeviceTree, 27 }; 28 use liberror::Result; 29 use mockall::mock; 30 31 /// Mock device_path module. 32 pub mod device_path { 33 use super::*; 34 35 mock! { 36 /// Mock [efi::DevicePathProtocol]. 37 pub DevicePathProtocol {} 38 } 39 /// Map to the libefi name so code under test can just use one name. 40 pub type DevicePathProtocol = MockDevicePathProtocol; 41 42 mock! { 43 /// Mock [efi::DevicePathToTextProtocol]. 44 pub DevicePathToTextProtocol { 45 /// Returns a [MockDevicePathText]. 46 /// 47 /// Lifetimes are a little difficult to mock perfectly, so here we can only allow a 48 /// `'static` return value. 49 pub fn convert_device_path_to_text( 50 &self, 51 device_path: &MockDevicePathProtocol, 52 display_only: bool, 53 allow_shortcuts: bool, 54 ) -> Result<MockDevicePathText<'static>>; 55 } 56 } 57 /// Map to the libefi name so code under test can just use one name. 58 pub type DevicePathToTextProtocol = MockDevicePathToTextProtocol; 59 60 mock! { 61 /// Mock [efi::DevicePathText]. 62 pub DevicePathText<'a> { 63 /// Returns the text, which is data-only so isn't mocked. 64 pub fn text(&self) -> Option<&'a [u16]>; 65 } 66 } 67 /// Map to the libefi name so code under test can just use one name. 68 pub type DevicePathText<'a> = MockDevicePathText<'a>; 69 } 70 71 /// Mock loaded_image protocol. 72 pub mod loaded_image { 73 use super::*; 74 75 mock! { 76 /// Mock [efi::LoadedImageProtocol]. 77 pub LoadedImageProtocol { 78 /// Returns a real [efi::DeviceHandle], which is data-only so isn't mocked. 79 pub fn device_handle(&self) -> Result<DeviceHandle>; 80 } 81 } 82 /// Map to the libefi name so code under test can just use one name. 83 pub type LoadedImageProtocol = MockLoadedImageProtocol; 84 } 85 86 /// Mock simple_text_input module. 87 pub mod simple_text_input { 88 use super::*; 89 90 mock! { 91 /// Mock [efi::SimpleTextInputProtocol]. 92 pub SimpleTextInputProtocol { 93 /// Returns an [EfiInputKey], which is data-only so isn't mocked. 94 pub fn read_key_stroke(&self) -> Result<Option<EfiInputKey>>; 95 } 96 } 97 /// Map to the libefi name so code under test can just use one name. 98 pub type SimpleTextInputProtocol = MockSimpleTextInputProtocol; 99 } 100 101 /// Mock simple_text_output module. 102 pub mod simple_text_output { 103 use super::*; 104 105 mock! { 106 /// Mock [efi::SimpleTextOutputProtocol]. 107 pub SimpleTextOutputProtocol {} 108 109 impl Write for SimpleTextOutputProtocol { 110 fn write_str(&mut self, s: &str) -> core::fmt::Result; 111 } 112 } 113 /// Map to the libefi name so code under test can just use one name. 114 pub type SimpleTextOutputProtocol = MockSimpleTextOutputProtocol; 115 116 /// Returns a [MockSimpleTextOutputProtocol] that forwards all calls to `MOCK_EFI`. passthrough_con_out() -> MockSimpleTextOutputProtocol117 pub fn passthrough_con_out() -> MockSimpleTextOutputProtocol { 118 let mut con_out = MockSimpleTextOutputProtocol::default(); 119 con_out.expect_write_str().returning(|s| { 120 MOCK_EFI.with_borrow_mut(|efi| efi.as_mut().unwrap().con_out.write_str(s)) 121 }); 122 con_out 123 } 124 125 /// While this mock itself isn't necessarily thread-local, passing through to the thread-local 126 /// state is our primary use case, so we just disallow [Send] entirely. 127 impl !Send for MockSimpleTextOutputProtocol {} 128 } 129 130 /// Mock image_loading protocol. 131 pub mod gbl_efi_image_loading { 132 use super::*; 133 134 pub use efi::protocol::gbl_efi_image_loading::EfiImageBufferInfo; 135 136 mock! { 137 /// Mock [efi::ImageLoadingProtocol]. 138 pub GblImageLoadingProtocol { 139 /// Returns [EfiImageBuffer] matching `gbl_image_info` 140 pub fn get_buffer(&self, gbl_image_info: &GblEfiImageInfo) -> Result<EfiImageBufferInfo>; 141 142 /// Returns number of partitions to be provided via `get_verify_partitions()`, and thus 143 /// expected size of `partition_name` slice. 144 pub fn get_verify_partitions_count(&self) -> Result<usize>; 145 146 /// Returns number of partition names written to `partition_name` slice. 147 pub fn get_verify_partitions( 148 &self, 149 partition_names: &mut [GblEfiPartitionName] 150 ) -> Result<usize>; 151 } 152 } 153 154 /// Map to the libefi name so code under test can just use one name. 155 pub type GblImageLoadingProtocol = MockGblImageLoadingProtocol; 156 } 157 158 /// Mock os_configuration protocol. 159 pub mod gbl_efi_os_configuration { 160 use super::*; 161 162 mock! { 163 /// Mock [efi::OsConfigurationProtocol]. 164 pub GblOsConfigurationProtocol { 165 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.fixup_kernel_commandline()` 166 pub fn fixup_kernel_commandline( 167 &self, 168 commandline: &CStr, 169 fixup: &mut [u8], 170 ) -> Result<()>; 171 172 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.fixup_bootconfig()` 173 pub fn fixup_bootconfig( 174 &self, 175 bootconfig: &[u8], 176 fixup: &mut [u8], 177 ) -> Result<usize>; 178 179 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.select_device_trees()` 180 pub fn select_device_trees( 181 &self, 182 components: &mut [GblEfiVerifiedDeviceTree], 183 ) -> Result<()>; 184 } 185 } 186 187 /// Map to the libefi name so code under test can just use one name. 188 pub type GblOsConfigurationProtocol = MockGblOsConfigurationProtocol; 189 } 190 191 /// Mock dt_fixup protocol. 192 pub mod dt_fixup { 193 use super::*; 194 195 mock! { 196 /// Mock [efi::DtFixupProtocol]. 197 pub DtFixupProtocol { 198 /// Wraps `EFI_DT_FIXUP_PROTOCOL.fixup()` 199 pub fn fixup(&self, device_tree: &mut [u8]) -> Result<()>; 200 } 201 } 202 203 /// Map to the libefi name so code under test can just use one name. 204 pub type DtFixupProtocol = MockDtFixupProtocol; 205 } 206 207 /// Mock avb protocol. 208 pub mod gbl_efi_avb { 209 use super::*; 210 211 /// Mock implementation of `GBL_EFI_AVB_PROTOCOL`. 212 /// We use a custom mock implementation instead of relying on `mockall` due to its limitations 213 /// regarding argument lifetimes. Specifically, in this case, `mockall` requires the 214 /// `validate_vbmeta_public_key.public_key_metadata` argument to have a `'static` lifetime, 215 /// which is not practical for our use case. 216 #[derive(Clone, Default)] 217 pub struct GblAvbProtocol { 218 /// Expected return value from `validate_vbmeta_public_key`. 219 pub validate_vbmeta_public_key_result: Option<Result<GblEfiAvbKeyValidationStatus>>, 220 /// Expected return value from `read_is_device_unlocked`. 221 pub read_is_device_unlocked_result: Option<Result<bool>>, 222 /// Expected return value from `read_rollback_index`. 223 pub read_rollback_index_result: Option<Result<u64>>, 224 /// Expected return value from `write_rollback_index`. 225 pub write_rollback_index_result: Option<Result<()>>, 226 /// Expected return value from `read_persistent_value`. 227 pub read_persistent_value_result: Option<Result<usize>>, 228 /// Expected return value from `write_persistent_value`. 229 pub write_persistent_value_result: Option<Result<()>>, 230 } 231 232 impl GblAvbProtocol { 233 /// Wraps `GBL_EFI_AVB_PROTOCOL.validate_vbmeta_public_key()`. validate_vbmeta_public_key( &self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> Result<GblEfiAvbKeyValidationStatus>234 pub fn validate_vbmeta_public_key( 235 &self, 236 _public_key: &[u8], 237 _public_key_metadata: Option<&[u8]>, 238 ) -> Result<GblEfiAvbKeyValidationStatus> { 239 self.validate_vbmeta_public_key_result.unwrap() 240 } 241 242 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_is_device_unlocked()`. read_is_device_unlocked(&self) -> Result<bool>243 pub fn read_is_device_unlocked(&self) -> Result<bool> { 244 self.read_is_device_unlocked_result.unwrap() 245 } 246 247 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_rollback_index()`. read_rollback_index(&self, _index_location: usize) -> Result<u64>248 pub fn read_rollback_index(&self, _index_location: usize) -> Result<u64> { 249 self.read_rollback_index_result.unwrap() 250 } 251 252 /// Wraps `GBL_EFI_AVB_PROTOCOL.write_rollback_index()`. write_rollback_index( &self, _index_location: usize, _rollback_index: u64, ) -> Result<()>253 pub fn write_rollback_index( 254 &self, 255 _index_location: usize, 256 _rollback_index: u64, 257 ) -> Result<()> { 258 self.write_rollback_index_result.unwrap() 259 } 260 261 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_persistent_value()`. read_persistent_value(&self, _name: &CStr, _value: &mut [u8]) -> Result<usize>262 pub fn read_persistent_value(&self, _name: &CStr, _value: &mut [u8]) -> Result<usize> { 263 self.read_persistent_value_result.unwrap() 264 } 265 266 /// Wraps `GBL_EFI_AVB_PROTOCOL.write_persistent_value()`. write_persistent_value(&self, _name: &CStr, _value: Option<&[u8]>) -> Result<()>267 pub fn write_persistent_value(&self, _name: &CStr, _value: Option<&[u8]>) -> Result<()> { 268 self.write_persistent_value_result.unwrap() 269 } 270 271 /// Wraps `GBL_EFI_AVB_PROTOCOL.handle_verification_result()`. handle_verification_result( &self, _verification_result: &GblEfiAvbVerificationResult, ) -> Result<()>272 pub fn handle_verification_result( 273 &self, 274 _verification_result: &GblEfiAvbVerificationResult, 275 ) -> Result<()> { 276 unimplemented!(); 277 } 278 } 279 } 280 281 /// Mock gbl_efi_fastboot protocol. 282 pub mod gbl_efi_fastboot { 283 use super::*; 284 285 mock! { 286 /// Mock [efi::protocol::gbl_efi_fastboot::Var]. 287 pub Var { 288 /// Get name, arguments and corresponding value. 289 pub fn get<'s>(&self, out: &mut [u8]) 290 -> Result<(&'static str, [&'static str; 1], &'static str)>; 291 } 292 } 293 294 /// Mock [efi::GblFastbootProtocol]. 295 pub struct GblFastbootProtocol {} 296 297 impl GblFastbootProtocol { 298 /// Protocol<'_, GblFastbootProtocol>::get_var. get_var<'a>( &self, _: &CStr, _: impl Iterator<Item = &'a CStr> + Clone, _: &mut [u8], ) -> Result<usize>299 pub fn get_var<'a>( 300 &self, 301 _: &CStr, 302 _: impl Iterator<Item = &'a CStr> + Clone, 303 _: &mut [u8], 304 ) -> Result<usize> { 305 unimplemented!() 306 } 307 308 /// Protocol<'_, GblFastbootProtocol>::get_var_all. get_var_all(&self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()>309 pub fn get_var_all(&self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()> { 310 unimplemented!() 311 } 312 } 313 314 /// Map to the libefi name so code under test can just use one name. 315 pub type Var = MockVar; 316 } 317 318 /// Mock gbl_efi_ab_slot 319 pub mod gbl_efi_ab_slot { 320 use super::*; 321 use efi::protocol::gbl_efi_ab_slot::GblSlot; 322 use efi_types::{GblEfiBootReason, GblEfiSlotMetadataBlock}; 323 324 mock! { 325 /// Mock of [GblSlotProtocol] 326 pub GblSlotProtocol { 327 /// Mock of GblSlotProtocol::get_current_slot. 328 pub fn get_current_slot(&self) -> Result<GblSlot>; 329 330 /// Mock of GblSlotProtocol::get_next_slot. 331 pub fn get_next_slot(&self, mark_boot_attempt: bool) -> Result<GblSlot>; 332 333 /// Mock of GblSlotProtocol::load_boot_data. 334 pub fn load_boot_data(&self) -> Result<GblEfiSlotMetadataBlock>; 335 336 /// Mock of GblSlotProtocol::set_active_slot. 337 pub fn set_active_slot(&self, idx: u8) -> Result<()>; 338 339 /// Mock of GblSlotProtocol::set_boot_reason. 340 pub fn set_boot_reason(&self, reason: GblEfiBootReason, subreason: &[u8]) -> Result<()>; 341 342 /// Mock of GblSlotProtocol::get_boot_reason. 343 pub fn get_boot_reason(&self, subreason: &mut [u8]) -> Result<(GblEfiBootReason, usize)>; 344 } 345 } 346 347 /// Map to the libefi name so code under test can just use one name. 348 pub type GblSlotProtocol = MockGblSlotProtocol; 349 } 350