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 use efi::protocol::gbl_efi_image_loading::EfiImageBuffer; 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 mock! { 135 /// Mock [efi::ImageLoadingProtocol]. 136 pub GblImageLoadingProtocol { 137 /// Returns [EfiImageBuffer] matching `gbl_image_info` 138 pub fn get_buffer(&self, gbl_image_info: &GblEfiImageInfo) -> Result<EfiImageBuffer>; 139 140 /// Returns number of partitions to be provided via `get_verify_partitions()`, and thus 141 /// expected size of `partition_name` slice. 142 pub fn get_verify_partitions_count(&self) -> Result<usize>; 143 144 /// Returns number of partition names written to `partition_name` slice. 145 pub fn get_verify_partitions( 146 &self, 147 partition_names: &mut [GblEfiPartitionName] 148 ) -> Result<usize>; 149 } 150 } 151 152 /// Map to the libefi name so code under test can just use one name. 153 pub type GblImageLoadingProtocol = MockGblImageLoadingProtocol; 154 } 155 156 /// Mock os_configuration protocol. 157 pub mod gbl_efi_os_configuration { 158 use super::*; 159 160 mock! { 161 /// Mock [efi::OsConfigurationProtocol]. 162 pub GblOsConfigurationProtocol { 163 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.fixup_kernel_commandline()` 164 pub fn fixup_kernel_commandline( 165 &self, 166 commandline: &CStr, 167 fixup: &[u8], 168 ) -> Result<()>; 169 170 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.fixup_bootconfig()` 171 pub fn fixup_bootconfig( 172 &self, 173 bootconfig: &[u8], 174 fixup: &mut [u8], 175 ) -> Result<usize>; 176 177 /// Wraps `GBL_EFI_OS_CONFIGURATION_PROTOCOL.select_device_trees()` 178 pub fn select_device_trees( 179 &self, 180 components: &mut [GblEfiVerifiedDeviceTree], 181 ) -> Result<()>; 182 } 183 } 184 185 /// Map to the libefi name so code under test can just use one name. 186 pub type GblOsConfigurationProtocol = MockGblOsConfigurationProtocol; 187 } 188 189 /// Mock dt_fixup protocol. 190 pub mod dt_fixup { 191 use super::*; 192 193 mock! { 194 /// Mock [efi::DtFixupProtocol]. 195 pub DtFixupProtocol { 196 /// Wraps `EFI_DT_FIXUP_PROTOCOL.fixup()` 197 pub fn fixup(&self, device_tree: &mut [u8]) -> Result<()>; 198 } 199 } 200 201 /// Map to the libefi name so code under test can just use one name. 202 pub type DtFixupProtocol = MockDtFixupProtocol; 203 } 204 205 /// Mock avb protocol. 206 pub mod gbl_efi_avb { 207 use super::*; 208 209 /// Mock implementation of `GBL_EFI_AVB_PROTOCOL`. 210 /// We use a custom mock implementation instead of relying on `mockall` due to its limitations 211 /// regarding argument lifetimes. Specifically, in this case, `mockall` requires the 212 /// `validate_vbmeta_public_key.public_key_metadata` argument to have a `'static` lifetime, 213 /// which is not practical for our use case. 214 #[derive(Clone, Default)] 215 pub struct GblAvbProtocol { 216 /// Expected return value from `validate_vbmeta_public_key`. 217 pub validate_vbmeta_public_key_result: Option<Result<GblEfiAvbKeyValidationStatus>>, 218 /// Expected return value from `read_is_device_unlocked`. 219 pub read_is_device_unlocked_result: Option<Result<bool>>, 220 /// Expected return value from `read_rollback_index`. 221 pub read_rollback_index_result: Option<Result<u64>>, 222 /// Expected return value from `write_rollback_index`. 223 pub write_rollback_index_result: Option<Result<()>>, 224 /// Expected return value from `read_persistent_value`. 225 pub read_persistent_value_result: Option<Result<usize>>, 226 /// Expected return value from `write_persistent_value`. 227 pub write_persistent_value_result: Option<Result<()>>, 228 } 229 230 impl GblAvbProtocol { 231 /// Wraps `GBL_EFI_AVB_PROTOCOL.validate_vbmeta_public_key()`. validate_vbmeta_public_key( &self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> Result<GblEfiAvbKeyValidationStatus>232 pub fn validate_vbmeta_public_key( 233 &self, 234 _public_key: &[u8], 235 _public_key_metadata: Option<&[u8]>, 236 ) -> Result<GblEfiAvbKeyValidationStatus> { 237 self.validate_vbmeta_public_key_result.unwrap() 238 } 239 240 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_is_device_unlocked()`. read_is_device_unlocked(&self) -> Result<bool>241 pub fn read_is_device_unlocked(&self) -> Result<bool> { 242 self.read_is_device_unlocked_result.unwrap() 243 } 244 245 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_rollback_index()`. read_rollback_index(&self, _index_location: usize) -> Result<u64>246 pub fn read_rollback_index(&self, _index_location: usize) -> Result<u64> { 247 self.read_rollback_index_result.unwrap() 248 } 249 250 /// Wraps `GBL_EFI_AVB_PROTOCOL.write_rollback_index()`. write_rollback_index( &self, _index_location: usize, _rollback_index: u64, ) -> Result<()>251 pub fn write_rollback_index( 252 &self, 253 _index_location: usize, 254 _rollback_index: u64, 255 ) -> Result<()> { 256 self.write_rollback_index_result.unwrap() 257 } 258 259 /// Wraps `GBL_EFI_AVB_PROTOCOL.read_persistent_value()`. read_persistent_value(&self, _name: &CStr, _value: &mut [u8]) -> Result<usize>260 pub fn read_persistent_value(&self, _name: &CStr, _value: &mut [u8]) -> Result<usize> { 261 self.read_persistent_value_result.unwrap() 262 } 263 264 /// Wraps `GBL_EFI_AVB_PROTOCOL.write_persistent_value()`. write_persistent_value(&self, _name: &CStr, _value: Option<&[u8]>) -> Result<()>265 pub fn write_persistent_value(&self, _name: &CStr, _value: Option<&[u8]>) -> Result<()> { 266 self.write_persistent_value_result.unwrap() 267 } 268 269 /// Wraps `GBL_EFI_AVB_PROTOCOL.handle_verification_result()`. handle_verification_result( &self, _verification_result: &GblEfiAvbVerificationResult, ) -> Result<()>270 pub fn handle_verification_result( 271 &self, 272 _verification_result: &GblEfiAvbVerificationResult, 273 ) -> Result<()> { 274 unimplemented!(); 275 } 276 } 277 } 278 279 /// Mock gbl_efi_fastboot protocol. 280 pub mod gbl_efi_fastboot { 281 use super::*; 282 283 mock! { 284 /// Mock [efi::protocol::gbl_efi_fastboot::Var]. 285 pub Var { 286 /// Get name, arguments and corresponding value. 287 pub fn get<'s>(&self, out: &mut [u8]) 288 -> Result<(&'static str, [&'static str; 1], &'static str)>; 289 } 290 } 291 292 /// Mock [efi::GblFastbootProtocol]. 293 pub struct GblFastbootProtocol {} 294 295 impl GblFastbootProtocol { 296 /// Protocol<'_, GblFastbootProtocol>::get_var. get_var<'a>( &self, _: &CStr, _: impl Iterator<Item = &'a CStr> + Clone, _: &mut [u8], ) -> Result<usize>297 pub fn get_var<'a>( 298 &self, 299 _: &CStr, 300 _: impl Iterator<Item = &'a CStr> + Clone, 301 _: &mut [u8], 302 ) -> Result<usize> { 303 unimplemented!() 304 } 305 306 /// Protocol<'_, GblFastbootProtocol>::get_var_all. get_var_all(&self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()>307 pub fn get_var_all(&self, _: impl FnMut(&[&CStr], &CStr)) -> Result<()> { 308 unimplemented!() 309 } 310 } 311 312 /// Map to the libefi name so code under test can just use one name. 313 pub type Var = MockVar; 314 } 315 316 /// Mock gbl_efi_ab_slot 317 pub mod gbl_efi_ab_slot { 318 use super::*; 319 use efi::protocol::gbl_efi_ab_slot::GblSlot; 320 use efi_types::{GblEfiBootReason, GblEfiSlotMetadataBlock}; 321 322 mock! { 323 /// Mock of [GblSlotProtocol] 324 pub GblSlotProtocol { 325 /// Mock of GblSlotProtocol::get_current_slot. 326 pub fn get_current_slot(&self) -> Result<GblSlot>; 327 328 /// Mock of GblSlotProtocol::get_next_slot. 329 pub fn get_next_slot(&self, mark_boot_attempt: bool) -> Result<GblSlot>; 330 331 /// Mock of GblSlotProtocol::load_boot_data. 332 pub fn load_boot_data(&self) -> Result<GblEfiSlotMetadataBlock>; 333 334 /// Mock of GblSlotProtocol::set_active_slot. 335 pub fn set_active_slot(&self, idx: u8) -> Result<()>; 336 337 /// Mock of GblSlotProtocol::set_boot_reason. 338 pub fn set_boot_reason(&self, reason: GblEfiBootReason, subreason: &[u8]) -> Result<()>; 339 340 /// Mock of GblSlotProtocol::get_boot_reason. 341 pub fn get_boot_reason(&self, subreason: &mut [u8]) -> Result<(GblEfiBootReason, usize)>; 342 } 343 } 344 345 /// Map to the libefi name so code under test can just use one name. 346 pub type GblSlotProtocol = MockGblSlotProtocol; 347 } 348