Skip to content

Commit c1375b5

Browse files
committed
Add safety docs & rework test for DiskIo2
1 parent 7a82e54 commit c1375b5

File tree

2 files changed

+64
-46
lines changed

2 files changed

+64
-46
lines changed

src/proto/media/disk.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ impl DiskIo2 {
126126
/// * `len` - Buffer size.
127127
/// * `buffer` - Buffer to read into.
128128
///
129+
/// # Safety:
130+
///
131+
/// Because of the asynchronous nature of the disk transaction, manual lifetime
132+
/// tracking is required.
133+
///
129134
/// # Errors:
130135
/// * `uefi::status::INVALID_PARAMETER` The read request contains device addresses
131136
/// that are not valid for the device.
@@ -155,6 +160,11 @@ impl DiskIo2 {
155160
/// * `len` - Buffer size.
156161
/// * `buffer` - Buffer to write from.
157162
///
163+
/// # Safety:
164+
///
165+
/// Because of the asynchronous nature of the disk transaction, manual lifetime
166+
/// tracking is required.
167+
///
158168
/// # Errors:
159169
/// * `uefi::status::INVALID_PARAMETER` The write request contains device addresses
160170
/// that are not valid for the device.

uefi-test-runner/src/proto/media/known_disk.rs

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -181,71 +181,79 @@ fn test_raw_disk_io(handle: Handle, image: Handle, bt: &BootServices) {
181181
bt.free_pool(buf).unwrap();
182182
}
183183

184+
/// Asynchronous disk I/O task context
185+
#[repr(C)]
186+
struct DiskIoTask {
187+
/// Token for the transaction
188+
token: DiskIo2Token,
189+
/// Pointer to a buffer holding the read data
190+
buffer: *mut u8,
191+
}
192+
184193
/// Asynchronous disk I/O 2 transaction callback
185194
unsafe extern "efiapi" fn disk_io2_callback(event: Event, ctx: Option<NonNull<c_void>>) {
186-
let ptr = ctx.unwrap().as_ptr() as *const u8;
195+
let task = ctx.unwrap().as_ptr() as *mut DiskIoTask;
187196

188197
// Verify that the disk's MBR signature is correct
189-
assert_eq!(*ptr.offset(510), 0x55);
190-
assert_eq!(*ptr.offset(511), 0xaa);
191-
192-
system_table()
193-
.as_ref()
194-
.boot_services()
195-
.close_event(event)
196-
.unwrap();
198+
assert_eq!((*task).token.transaction_status, uefi::Status::SUCCESS);
199+
assert_eq!(*(*task).buffer.offset(510), 0x55);
200+
assert_eq!(*(*task).buffer.offset(511), 0xaa);
201+
202+
// Close the completion event
203+
let bt = system_table().as_ref().boot_services();
204+
bt.close_event(event).unwrap();
205+
206+
// Free the disk data buffer & task context
207+
bt.free_pool((*task).buffer).unwrap();
208+
bt.free_pool(task as *mut u8).unwrap();
197209
}
198210

199211
/// Tests raw disk I/O through the DiskIo2 protocol.
200212
fn test_raw_disk_io2(handle: Handle, image: Handle, bt: &BootServices) {
201213
info!("Testing raw disk I/O 2");
202214

203215
// Open the disk I/O protocol on the input handle
204-
let disk_io2 = bt.open_protocol::<DiskIo2>(
216+
if let Ok(disk_io2) = bt.open_protocol::<DiskIo2>(
205217
OpenProtocolParams {
206218
handle,
207219
agent: image,
208220
controller: None,
209221
},
210222
OpenProtocolAttributes::GetProtocol,
211-
);
212-
if disk_io2.is_err() {
213-
return;
214-
}
215-
216-
let disk_io2 = disk_io2.unwrap();
217-
218-
// Allocate a temporary buffer to read into
219-
const SIZE: usize = 512;
220-
let buf = bt
221-
.allocate_pool(MemoryType::LOADER_DATA, SIZE)
222-
.expect("Failed to allocate temporary buffer");
223-
224-
// Create an event callback for the disk read completion
225-
let event = unsafe {
226-
bt.create_event(
227-
EventType::NOTIFY_SIGNAL,
228-
Tpl::NOTIFY,
229-
Some(disk_io2_callback),
230-
NonNull::new(buf as *mut c_void),
231-
)
232-
.expect("Failed to create event for disk I/O 2 transaction")
233-
};
223+
) {
224+
// Allocate the task context structure
225+
let task = bt
226+
.allocate_pool(MemoryType::LOADER_DATA, core::mem::size_of::<DiskIoTask>())
227+
.expect("Failed to allocate task struct for disk I/O")
228+
as *mut DiskIoTask;
229+
230+
// SAFETY: `task` refers to a valid allocation of at least `size_of::<DiskIoTask>()`
231+
unsafe {
232+
// Create the completion event as part of the disk I/O token
233+
(*task).token.event = Some(
234+
bt.create_event(
235+
EventType::NOTIFY_SIGNAL,
236+
Tpl::NOTIFY,
237+
Some(disk_io2_callback),
238+
NonNull::new(task as *mut c_void),
239+
)
240+
.expect("Failed to create disk I/O completion event"),
241+
);
242+
243+
// Allocate a buffer for the transaction to read into
244+
const SIZE_TO_READ: usize = 512;
245+
(*task).buffer = bt
246+
.allocate_pool(MemoryType::LOADER_DATA, SIZE_TO_READ)
247+
.expect("Failed to allocate buffer for disk I/O");
248+
249+
// Initiate the asynchronous read operation
250+
disk_io2
251+
.read_disk_raw(0, 0, &mut (*task).token, SIZE_TO_READ, (*task).buffer)
252+
.expect("Failed to initiate asynchronous disk I/O read");
253+
}
234254

235-
// Read from the first sector of the disk into the buffer
236-
// SAFETY: The cloned `event` is only used for this transaction
237-
unsafe {
238-
let mut token = DiskIo2Token {
239-
event: Some(event.unsafe_clone()),
240-
transaction_status: uefi::Status::SUCCESS,
241-
};
242-
disk_io2
243-
.read_disk_raw(0, 0, &mut token, SIZE, buf)
244-
.expect("Failed to read from disk");
255+
info!("Raw disk I/O 2 succeeded");
245256
}
246-
247-
info!("Raw disk I/O 2 succeeded");
248-
bt.free_pool(buf).unwrap();
249257
}
250258

251259
/// Run various tests on a special test disk. The disk is created by

0 commit comments

Comments
 (0)