• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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