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