1 | //! Disk I/O protocols. |
2 | |
3 | use crate::proto::unsafe_protocol ; |
4 | use crate::{Event, Result, Status}; |
5 | use 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" )] |
15 | pub 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 | |
33 | impl 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)] |
74 | pub 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" )] |
87 | pub 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 | |
110 | impl 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 | |