xref: /aosp_15_r20/bootable/libbootloader/gbl/libefi/src/protocol/block_io.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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 //! Rust wrapper for `EFI_BLOCK_IO_PROTOCOL`.
16 
17 use crate::efi_call;
18 use crate::protocol::{Protocol, ProtocolInfo};
19 use efi_types::{EfiBlockIoMedia, EfiBlockIoProtocol, EfiGuid};
20 use gbl_storage::SliceMaybeUninit;
21 use liberror::{Error, Result};
22 
23 /// EFI_BLOCK_IO_PROTOCOL
24 pub struct BlockIoProtocol;
25 
26 impl ProtocolInfo for BlockIoProtocol {
27     type InterfaceType = EfiBlockIoProtocol;
28 
29     const GUID: EfiGuid =
30         EfiGuid::new(0x964e5b21, 0x6459, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b]);
31 }
32 
33 // Protocol interface wrappers.
34 impl Protocol<'_, BlockIoProtocol> {
35     /// Wrapper of `EFI_BLOCK_IO_PROTOCOL.read_blocks()`
read_blocks( &self, lba: u64, buffer: &mut (impl SliceMaybeUninit + ?Sized), ) -> Result<()>36     pub fn read_blocks(
37         &self,
38         lba: u64,
39         buffer: &mut (impl SliceMaybeUninit + ?Sized),
40     ) -> Result<()> {
41         // SAFETY:
42         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
43         // established by `Protocol::new()`.
44         // `self.interface` is input parameter and will not be retained. It outlives the call.
45         // `buffer` remains valid during the call.
46         unsafe {
47             efi_call!(
48                 self.interface()?.read_blocks,
49                 self.interface,
50                 self.media()?.media_id,
51                 lba,
52                 buffer.len(),
53                 buffer.as_mut().as_mut_ptr() as *mut _
54             )
55         }
56     }
57 
58     /// Wrapper of `EFI_BLOCK_IO_PROTOCOL.write_blocks()`
write_blocks(&self, lba: u64, buffer: &mut [u8]) -> Result<()>59     pub fn write_blocks(&self, lba: u64, buffer: &mut [u8]) -> Result<()> {
60         // SAFETY:
61         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
62         // established by `Protocol::new()`.
63         // `self.interface` is input parameter and will not be retained. It outlives the call.
64         // `buffer` remains valid during the call.
65         unsafe {
66             efi_call!(
67                 self.interface()?.write_blocks,
68                 self.interface,
69                 self.media()?.media_id,
70                 lba,
71                 buffer.len(),
72                 buffer.as_mut_ptr() as _
73             )
74         }
75     }
76 
77     /// Wrapper of `EFI_BLOCK_IO_PROTOCOL.flush_blocks()`
flush_blocks(&self) -> Result<()>78     pub fn flush_blocks(&self) -> Result<()> {
79         // SAFETY:
80         // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
81         // established by `Protocol::new()`.
82         // `self.interface` is input parameter and will not be retained. It outlives the call.
83         unsafe { efi_call!(self.interface()?.flush_blocks, self.interface) }
84     }
85 
86     /// Wrapper of `EFI_BLOCK_IO_PROTOCOL.reset()`
reset(&self, extended_verification: bool) -> Result<()>87     pub fn reset(&self, extended_verification: bool) -> Result<()> {
88         // SAFETY:
89         // `self.interface()?` guarantees `self.interface` is non-null and points to a valid object
90         // established by `Protocol::new()`.
91         // `self.interface` is input parameter and will not be retained. It outlives the call.
92         unsafe { efi_call!(self.interface()?.reset, self.interface, extended_verification) }
93     }
94 
95     /// Get a copy to the EFI_BLOCK_IO_PROTOCOL.Media structure.
media(&self) -> Result<EfiBlockIoMedia>96     pub fn media(&self) -> Result<EfiBlockIoMedia> {
97         let ptr = self.interface()?.media;
98         // SFETY: Pointers to EFI data structure.
99         Ok(*unsafe { ptr.as_ref() }.ok_or(Error::InvalidInput)?)
100     }
101 }
102