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