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