1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
//! Disk I/O protocols.
use crate::proto::unsafe_protocol;
use crate::util::opt_nonnull_to_ptr;
use crate::{Event, Result, Status, StatusExt};
use core::ptr::NonNull;
use uefi_raw::protocol::disk::{DiskIo2Protocol, DiskIoProtocol};
/// The disk I/O protocol.
///
/// This protocol is used to abstract the block accesses of the block I/O
/// protocol to a more general offset-length protocol. Firmware is
/// responsible for adding this protocol to any block I/O interface that
/// appears in the system that does not already have a disk I/O protocol.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(DiskIoProtocol::GUID)]
pub struct DiskIo(DiskIoProtocol);
impl DiskIo {
/// Reads bytes from the disk device.
///
/// # Arguments:
/// * `media_id` - ID of the medium to be read.
/// * `offset` - Starting byte offset on the logical block I/O device to read from.
/// * `buffer` - Pointer to a buffer to read into.
///
/// # Errors:
/// * `uefi::status::INVALID_PARAMETER` The read request contains device addresses that
/// are not valid for the device.
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the read operation.
/// * `uefi::status::NO_MEDIA` There is no medium in the device.
/// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium.
pub fn read_disk(&self, media_id: u32, offset: u64, buffer: &mut [u8]) -> Result {
unsafe {
(self.0.read_disk)(
&self.0,
media_id,
offset,
buffer.len(),
buffer.as_mut_ptr().cast(),
)
}
.to_result()
}
/// Writes bytes to the disk device.
///
/// # Arguments:
/// * `media_id` - ID of the medium to be written.
/// * `offset` - Starting byte offset on the logical block I/O device to write to.
/// * `buffer` - Pointer to a buffer to write from.
///
/// # Errors:
/// * `uefi::status::INVALID_PARAMETER` The write request contains device addresses that
/// are not valid for the device.
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the write operation.
/// * `uefi::status::NO_MEDIA` There is no medium in the device.
/// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium.
/// * `uefi::status::WRITE_PROTECTED` The device cannot be written to.
pub fn write_disk(&mut self, media_id: u32, offset: u64, buffer: &[u8]) -> Result {
unsafe {
(self.0.write_disk)(
&mut self.0,
media_id,
offset,
buffer.len(),
buffer.as_ptr().cast(),
)
}
.to_result()
}
}
/// Asynchronous transaction token for disk I/O 2 operations.
#[repr(C)]
#[derive(Debug)]
pub struct DiskIo2Token {
/// Event to be signalled when an asynchronous disk I/O operation completes.
pub event: Option<Event>,
/// Transaction status code.
pub transaction_status: Status,
}
/// The disk I/O 2 protocol.
///
/// This protocol provides an extension to the disk I/O protocol to enable
/// non-blocking / asynchronous byte-oriented disk operation.
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(DiskIo2Protocol::GUID)]
pub struct DiskIo2(DiskIo2Protocol);
impl DiskIo2 {
/// Terminates outstanding asynchronous requests to the device.
///
/// # Errors:
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the cancel operation.
pub fn cancel(&mut self) -> Result {
unsafe { (self.0.cancel)(&mut self.0) }.to_result()
}
/// Reads bytes from the disk device.
///
/// # Arguments:
/// * `media_id` - ID of the medium to be read from.
/// * `offset` - Starting byte offset on the logical block I/O device to read from.
/// * `token` - Transaction token for asynchronous read.
/// * `len` - Buffer size.
/// * `buffer` - Buffer to read into.
///
/// # Safety
///
/// Because of the asynchronous nature of the disk transaction, manual lifetime
/// tracking is required.
///
/// # Errors:
/// * `uefi::status::INVALID_PARAMETER` The read request contains device addresses
/// that are not valid for the device.
/// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to
/// a lack of resources.
/// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium.
/// * `uefi::status::NO_MEDIA` There is no medium in the device.
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the read operation.
pub unsafe fn read_disk_raw(
&self,
media_id: u32,
offset: u64,
token: Option<NonNull<DiskIo2Token>>,
len: usize,
buffer: *mut u8,
) -> Result {
let token = opt_nonnull_to_ptr(token);
(self.0.read_disk_ex)(&self.0, media_id, offset, token.cast(), len, buffer.cast())
.to_result()
}
/// Writes bytes to the disk device.
///
/// # Arguments:
/// * `media_id` - ID of the medium to write to.
/// * `offset` - Starting byte offset on the logical block I/O device to write to.
/// * `token` - Transaction token for asynchronous write.
/// * `len` - Buffer size.
/// * `buffer` - Buffer to write from.
///
/// # Safety
///
/// Because of the asynchronous nature of the disk transaction, manual lifetime
/// tracking is required.
///
/// # Errors:
/// * `uefi::status::INVALID_PARAMETER` The write request contains device addresses
/// that are not valid for the device.
/// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to
/// a lack of resources.
/// * `uefi::status::MEDIA_CHANGED` `media_id` is not for the current medium.
/// * `uefi::status::NO_MEDIA` There is no medium in the device.
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the write operation.
/// * `uefi::status::WRITE_PROTECTED` The device cannot be written to.
pub unsafe fn write_disk_raw(
&mut self,
media_id: u32,
offset: u64,
token: Option<NonNull<DiskIo2Token>>,
len: usize,
buffer: *const u8,
) -> Result {
let token = opt_nonnull_to_ptr(token);
(self.0.write_disk_ex)(
&mut self.0,
media_id,
offset,
token.cast(),
len,
buffer.cast(),
)
.to_result()
}
/// Flushes all modified data to the physical device.
///
/// # Arguments:
/// * `token` - Transaction token for the asynchronous flush.
///
/// # Errors:
/// * `uefi::status::OUT_OF_RESOURCES` The request could not be completed due to
/// a lack of resources.
/// * `uefi::status::MEDIA_CHANGED` The medium in the device has changed since
/// the last access.
/// * `uefi::status::NO_MEDIA` There is no medium in the device.
/// * `uefi::status::DEVICE_ERROR` The device reported an error while performing
/// the flush operation.
/// * `uefi::status::WRITE_PROTECTED` The device cannot be written to.
pub fn flush_disk(&mut self, token: Option<NonNull<DiskIo2Token>>) -> Result {
let token = opt_nonnull_to_ptr(token);
unsafe { (self.0.flush_disk_ex)(&mut self.0, token.cast()) }.to_result()
}
}