-
-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathdisk.rs
213 lines (202 loc) · 7.56 KB
/
disk.rs
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
205
206
207
208
209
210
211
212
213
// SPDX-License-Identifier: MIT OR Apache-2.0
//! 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
/// * [`Status::INVALID_PARAMETER`] when the read request contains device
/// addresses that are not valid for the device.
/// * [`Status::DEVICE_ERROR`] when the device reported an error while
/// performing the read operation.
/// * [`Status::NO_MEDIA`] when there is no medium in the device.
/// * [`Status::MEDIA_CHANGED`] when `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
/// * [`Status::INVALID_PARAMETER`] when the write request contains device
/// addresses that are not valid for the device.
/// * [`Status::DEVICE_ERROR`] when the device reported an error while
/// performing the write operation.
/// * [`Status::NO_MEDIA`] when there is no medium in the device.
/// * [`Status::MEDIA_CHANGED`] then `media_id` is not for the current
/// medium.
/// * [`Status::WRITE_PROTECTED`] when 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
/// * [`Status::DEVICE_ERROR`] The device reported an error while performing
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
/// * [`Status::INVALID_PARAMETER`] when the read request contains device
/// addresses that are not valid for the device.
/// * [`Status::OUT_OF_RESOURCES`] when the request could not be completed
/// due to a lack of resources.
/// * [`Status::MEDIA_CHANGED`] when `media_id` is not for the current
/// medium.
/// * [`Status::NO_MEDIA`] when there is no medium in the device.
/// * [`Status::DEVICE_ERROR`] when 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);
unsafe {
(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
/// * [`Status::INVALID_PARAMETER`] when the write request contains device
/// addresses that are not valid for the device.
/// * [`Status::OUT_OF_RESOURCES`] when the request could not be completed
/// due to a lack of resources.
/// * [`Status::MEDIA_CHANGED`] when `media_id` is not for the current
/// medium.
/// * [`Status::NO_MEDIA`] when there is no medium in the device.
/// * [`Status::DEVICE_ERROR`] when the device reported an error while
/// performing the write operation.
/// * [`Status::WRITE_PROTECTED`] when 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);
unsafe {
(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
/// * [`Status::OUT_OF_RESOURCES`] when the request could not be completed
/// due to a lack of resources.
/// * [`Status::MEDIA_CHANGED`] when the medium in the device has changed
/// since the last access.
/// * [`Status::NO_MEDIA`] when there is no medium in the device.
/// * [`Status::DEVICE_ERROR`] when the device reported an error while
/// performing the flush operation.
/// * [`Status::WRITE_PROTECTED`] when 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()
}
}