Skip to content

Commit 67b855e

Browse files
committed
uefi: add BlockIO2 protocol wrapper
1 parent 0bcde9a commit 67b855e

File tree

2 files changed

+134
-3
lines changed

2 files changed

+134
-3
lines changed

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
- Added `proto::pci::root_bridge::PciRootBridgeIo::configuration()`.
77
- Added `proto::pci::root_bridge::PciRootBridgeIo::enumerate()`.
88
- Added `proto::nvme::pass_thru::NvmePassThru::broadcast()`.
9+
- Added `proto::media::block::BlockIO2`.
910

1011
## Changed
1112
- Changed ordering of `proto::pci::PciIoAddress` to (bus -> dev -> fun -> reg -> ext_reg).

uefi/src/proto/media/block.rs

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

3-
//! Block I/O protocols.
3+
//! Block I/O protocols [`BlockIO`] and [`BlockIO2`].
4+
5+
use core::ptr::NonNull;
46

57
use crate::proto::unsafe_protocol;
6-
use crate::{Result, StatusExt};
8+
use crate::util::opt_nonnull_to_ptr;
9+
use crate::{Event, Result, Status, StatusExt};
710

8-
pub use uefi_raw::protocol::block::{BlockIoProtocol, Lba};
11+
pub use uefi_raw::protocol::block::{BlockIo2Protocol, BlockIoProtocol, Lba};
912

1013
/// Block I/O [`Protocol`].
1114
///
@@ -186,3 +189,130 @@ impl BlockIOMedia {
186189
self.0.optimal_transfer_length_granularity
187190
}
188191
}
192+
193+
/// Asynchronous transaction token for Block I/O 2 operations.
194+
#[repr(C)]
195+
#[derive(Debug)]
196+
pub struct BlockIO2Token {
197+
/// Event to be signalled when an asynchronous block I/O operation
198+
/// completes.
199+
pub event: Option<Event>,
200+
/// Transaction status code.
201+
pub transaction_status: Status,
202+
}
203+
204+
/// Block I/O 2 [`Protocol`].
205+
///
206+
/// The Block I/O 2 protocol defines an extension to the Block I/O protocol
207+
/// which enables the ability to read and write data at a block level in a
208+
/// non-blocking manner.
209+
///
210+
/// [`Protocol`]: uefi::proto::Protocol
211+
#[derive(Debug)]
212+
#[repr(transparent)]
213+
#[unsafe_protocol(BlockIo2Protocol::GUID)]
214+
pub struct BlockIO2(BlockIo2Protocol);
215+
216+
impl BlockIO2 {
217+
/// Pointer for block IO media.
218+
#[must_use]
219+
pub const fn media(&self) -> &BlockIOMedia {
220+
unsafe { &*self.0.media.cast::<BlockIOMedia>() }
221+
}
222+
223+
/// Resets the block device hardware.
224+
///
225+
/// # Arguments
226+
/// * `extended_verification` - Indicates that the driver may perform a more exhaustive verification operation of the device during reset.
227+
///
228+
/// # Errors
229+
/// * [`Status::DEVICE_ERROR`] The block device is not functioning correctly and could not be reset.
230+
pub fn reset(&mut self, extended_verification: bool) -> Result {
231+
unsafe { (self.0.reset)(&mut self.0, extended_verification.into()) }.to_result()
232+
}
233+
234+
/// Reads the requested number of blocks from the device.
235+
///
236+
/// # Arguments
237+
/// * `media_id` - The media ID that the read request is for.
238+
/// * `lba` - The starting logical block address to read from on the device.
239+
/// * `token` - Transaction token for asynchronous read.
240+
/// * `len` - Buffer size.
241+
/// * `buffer` - The target buffer of the read operation
242+
///
243+
/// # Safety
244+
/// Because of the asynchronous nature of the block transaction, manual lifetime
245+
/// tracking is required.
246+
///
247+
/// # Errors
248+
/// * [`Status::INVALID_PARAMETER`] The read request contains LBAs that are not valid, or the buffer is not on proper alignment.
249+
/// * [`Status::OUT_OF_RESOURCES`] The request could not be completed due to a lack of resources.
250+
/// * [`Status::MEDIA_CHANGED`] The `media_id` is not for the current media.
251+
/// * [`Status::NO_MEDIA`] There is no media in the device.
252+
/// * [`Status::DEVICE_ERROR`] The device reported an error while performing the read operation.
253+
/// * [`Status::BAD_BUFFER_SIZE`] The buffer size parameter is not a multiple of the intrinsic block size of the device.
254+
pub unsafe fn read_blocks_ex(
255+
&self,
256+
media_id: u32,
257+
lba: Lba,
258+
token: Option<NonNull<BlockIO2Token>>,
259+
len: usize,
260+
buffer: *mut u8,
261+
) -> Result {
262+
let token = opt_nonnull_to_ptr(token);
263+
unsafe { (self.0.read_blocks_ex)(&self.0, media_id, lba, token.cast(), len, buffer.cast()) }
264+
.to_result()
265+
}
266+
267+
/// Writes a specified number of blocks to the device.
268+
///
269+
/// # Arguments
270+
/// * `media_id` - The media ID that the write request is for.
271+
/// * `lba` - The starting logical block address to be written.
272+
/// * `token` - Transaction token for asynchronous write.
273+
/// * `len` - Buffer size.
274+
/// * `buffer` - Buffer to be written from.
275+
///
276+
/// # Safety
277+
/// Because of the asynchronous nature of the block transaction, manual
278+
/// lifetime tracking is required.
279+
///
280+
/// # Errors
281+
/// * [`Status::INVALID_PARAMETER`] The write request contains LBAs that are not valid, or the buffer is not on proper alignment.
282+
/// * [`Status::OUT_OF_RESOURCES`] The request could not be completed due to a lack of resources.
283+
/// * [`Status::MEDIA_CHANGED`] The `media_id` is not for the current media.
284+
/// * [`Status::NO_MEDIA`] There is no media in the device.
285+
/// * [`Status::DEVICE_ERROR`] The device reported an error while performing the write operation.
286+
/// * [`Status::WRITE_PROTECTED`] The device cannot be written to.
287+
/// * [`Status::BAD_BUFFER_SIZE`] The buffer size parameter is not a multiple of the intrinsic block size of the device.
288+
pub unsafe fn write_blocks_ex(
289+
&mut self,
290+
media_id: u32,
291+
lba: Lba,
292+
token: Option<NonNull<BlockIO2Token>>,
293+
len: usize,
294+
buffer: *const u8,
295+
) -> Result {
296+
let token = opt_nonnull_to_ptr(token);
297+
unsafe {
298+
(self.0.write_blocks_ex)(&mut self.0, media_id, lba, token.cast(), len, buffer.cast())
299+
}
300+
.to_result()
301+
}
302+
303+
/// Flushes all modified data to the physical device.
304+
///
305+
/// # Arguments
306+
/// * `token` - Transaction token for asynchronous flush.
307+
///
308+
/// # Errors
309+
/// * [`Status::OUT_OF_RESOURCES`] The request could not be completed due to a lack of resources.
310+
/// * [`Status::MEDIA_CHANGED`] The media in the device has changed since the last access.
311+
/// * [`Status::NO_MEDIA`] There is no media in the device.
312+
/// * [`Status::DEVICE_ERROR`] The `media_id` is not for the current media.
313+
/// * [`Status::WRITE_PROTECTED`] The device cannot be written to.
314+
pub fn flush_blocks_ex(&mut self, token: Option<NonNull<BlockIO2Token>>) -> Result {
315+
let token = opt_nonnull_to_ptr(token);
316+
unsafe { (self.0.flush_blocks_ex)(&mut self.0, token.cast()) }.to_result()
317+
}
318+
}

0 commit comments

Comments
 (0)