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