1 //! Block I/O protocols.
2 
3 use crate::proto::unsafe_protocol;
4 use crate::{Result, StatusExt};
5 
6 pub use uefi_raw::protocol::block::{BlockIoProtocol, Lba};
7 
8 /// The Block I/O protocol.
9 #[derive(Debug)]
10 #[repr(transparent)]
11 #[unsafe_protocol(BlockIoProtocol::GUID)]
12 pub struct BlockIO(BlockIoProtocol);
13 
14 impl BlockIO {
15     /// Pointer for block IO media.
16     #[must_use]
media(&self) -> &BlockIOMedia17     pub const fn media(&self) -> &BlockIOMedia {
18         unsafe { &*self.0.media.cast::<BlockIOMedia>() }
19     }
20 
21     /// Resets the block device hardware.
22     ///
23     /// # Arguments
24     /// * `extended_verification`   Indicates that the driver may perform a more exhaustive verification operation of
25     ///     the device during reset.
26     ///
27     /// # Errors
28     /// * `uefi::Status::DEVICE_ERROR`  The block device is not functioning correctly and could not be reset.
reset(&mut self, extended_verification: bool) -> Result29     pub fn reset(&mut self, extended_verification: bool) -> Result {
30         unsafe { (self.0.reset)(&mut self.0, extended_verification) }.to_result()
31     }
32 
33     /// Read the requested number of blocks from the device.
34     ///
35     /// # Arguments
36     /// * `media_id` - The media ID that the read request is for.
37     /// * `lba` - The starting logical block address to read from on the device.
38     /// * `buffer` - The target buffer of the read operation
39     ///
40     /// # Errors
41     /// * `uefi::Status::DEVICE_ERROR`       The device reported an error while attempting to perform the read
42     ///     operation.
43     /// * `uefi::Status::NO_MEDIA`           There is no media in the device.
44     /// * `uefi::Status::MEDIA_CHANGED`      The `media_id` is not for the current media.
45     /// * `uefi::Status::BAD_BUFFER_SIZE`    The buffer size parameter is not a multiple of the intrinsic block size of
46     ///     the device.
47     /// * `uefi::Status::INVALID_PARAMETER`  The read request contains LBAs that are not valid, or the buffer is not on
48     ///     proper alignment.
read_blocks(&self, media_id: u32, lba: Lba, buffer: &mut [u8]) -> Result49     pub fn read_blocks(&self, media_id: u32, lba: Lba, buffer: &mut [u8]) -> Result {
50         let buffer_size = buffer.len();
51         unsafe {
52             (self.0.read_blocks)(
53                 &self.0,
54                 media_id,
55                 lba,
56                 buffer_size,
57                 buffer.as_mut_ptr().cast(),
58             )
59         }
60         .to_result()
61     }
62 
63     /// Writes the requested number of blocks to the device.
64     ///
65     /// # Arguments
66     /// * `media_id`    The media ID that the write request is for.
67     /// * `lba`         The starting logical block address to be written.
68     /// * `buffer`      Buffer to be written
69     ///
70     /// # Errors
71     /// * `uefi::Status::WRITE_PROTECTED`       The device cannot be written to.
72     /// * `uefi::Status::NO_MEDIA`              There is no media in the device.
73     /// * `uefi::Status::MEDIA_CHANGED`         The `media_id` is not for the current media.
74     /// * `uefi::Status::DEVICE_ERROR`          The device reported an error while attempting to perform the write
75     ///     operation.
76     /// * `uefi::Status::BAD_BUFFER_SIZE`       The buffer size parameter is not a multiple of the intrinsic block size
77     ///     of the device.
78     /// * `uefi::Status::INVALID_PARAMETER`     The write request contains LBAs that are not valid, or the buffer is not
79     ///     on proper alignment.
write_blocks(&mut self, media_id: u32, lba: Lba, buffer: &[u8]) -> Result80     pub fn write_blocks(&mut self, media_id: u32, lba: Lba, buffer: &[u8]) -> Result {
81         let buffer_size = buffer.len();
82         unsafe {
83             (self.0.write_blocks)(
84                 &mut self.0,
85                 media_id,
86                 lba,
87                 buffer_size,
88                 buffer.as_ptr().cast(),
89             )
90         }
91         .to_result()
92     }
93 
94     /// Flushes all modified data to a physical block device.
95     ///
96     /// # Errors
97     /// * `uefi::Status::DEVICE_ERROR`          The device reported an error while attempting to write data.
98     /// * `uefi::Status::NO_MEDIA`              There is no media in the device.
flush_blocks(&mut self) -> Result99     pub fn flush_blocks(&mut self) -> Result {
100         unsafe { (self.0.flush_blocks)(&mut self.0) }.to_result()
101     }
102 }
103 
104 /// Media information structure
105 #[repr(transparent)]
106 #[derive(Debug)]
107 pub struct BlockIOMedia(uefi_raw::protocol::block::BlockIoMedia);
108 
109 impl BlockIOMedia {
110     /// The current media ID.
111     #[must_use]
media_id(&self) -> u32112     pub const fn media_id(&self) -> u32 {
113         self.0.media_id
114     }
115 
116     /// True if the media is removable.
117     #[must_use]
is_removable_media(&self) -> bool118     pub const fn is_removable_media(&self) -> bool {
119         self.0.removable_media
120     }
121 
122     /// True if there is a media currently present in the device.
123     #[must_use]
is_media_present(&self) -> bool124     pub const fn is_media_present(&self) -> bool {
125         self.0.media_present
126     }
127 
128     /// True if block IO was produced to abstract partition structure.
129     #[must_use]
is_logical_partition(&self) -> bool130     pub const fn is_logical_partition(&self) -> bool {
131         self.0.logical_partition
132     }
133 
134     /// True if the media is marked read-only.
135     #[must_use]
is_read_only(&self) -> bool136     pub const fn is_read_only(&self) -> bool {
137         self.0.read_only
138     }
139 
140     /// True if `writeBlocks` function writes data.
141     #[must_use]
is_write_caching(&self) -> bool142     pub const fn is_write_caching(&self) -> bool {
143         self.0.write_caching
144     }
145 
146     /// The intrinsic block size of the device.
147     ///
148     /// If the media changes, then this field is updated. Returns the number of bytes per logical block.
149     #[must_use]
block_size(&self) -> u32150     pub const fn block_size(&self) -> u32 {
151         self.0.block_size
152     }
153 
154     /// Supplies the alignment requirement for any buffer used in a data transfer.
155     #[must_use]
io_align(&self) -> u32156     pub const fn io_align(&self) -> u32 {
157         self.0.io_align
158     }
159 
160     /// The last LBA on the device. If the media changes, then this field is updated.
161     #[must_use]
last_block(&self) -> Lba162     pub const fn last_block(&self) -> Lba {
163         self.0.last_block
164     }
165 
166     /// Returns the first LBA that is aligned to a physical block boundary.
167     #[must_use]
lowest_aligned_lba(&self) -> Lba168     pub const fn lowest_aligned_lba(&self) -> Lba {
169         self.0.lowest_aligned_lba
170     }
171 
172     /// Returns the number of logical blocks per physical block.
173     #[must_use]
logical_blocks_per_physical_block(&self) -> u32174     pub const fn logical_blocks_per_physical_block(&self) -> u32 {
175         self.0.logical_blocks_per_physical_block
176     }
177 
178     /// Returns the optimal transfer length granularity as a number of logical blocks.
179     #[must_use]
optimal_transfer_length_granularity(&self) -> u32180     pub const fn optimal_transfer_length_granularity(&self) -> u32 {
181         self.0.optimal_transfer_length_granularity
182     }
183 }
184