1 | //! Block I/O protocols. |
2 | |
3 | use crate::proto::unsafe_protocol ; |
4 | use crate::{Result, Status}; |
5 | |
6 | /// The Block I/O protocol. |
7 | #[repr (C)] |
8 | #[unsafe_protocol ("964e5b21-6459-11d2-8e39-00a0c969723b" )] |
9 | pub 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 | |
31 | impl 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 |
104 | pub type Lba = u64; |
105 | |
106 | /// Media information structure |
107 | #[repr (C)] |
108 | #[derive (Debug)] |
109 | pub 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 | |
129 | impl 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 | |