Skip to content

uefi: Add safe protocol wrapper for EFI_ATA_PASS_THRU_PROTOCOL #1595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions uefi-test-runner/src/proto/ata/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

mod pass_thru;

pub fn test() {
pass_thru::test();
}
59 changes: 59 additions & 0 deletions uefi-test-runner/src/proto/ata/pass_thru.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

use uefi::boot;
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams};
use uefi::proto::ata::pass_thru::AtaPassThru;
use uefi::proto::ata::AtaRequestBuilder;

pub fn test() {
info!("Running ATA PassThru tests");

assert!(is_testdrive_present());
}

const ATACMD_IDENTIFY: u8 = 0xEC;

fn is_testdrive_present() -> bool {
let ata_ctrl_handles = boot::find_handles::<AtaPassThru>().unwrap();
assert_eq!(ata_ctrl_handles.len(), 1);

for handle in ata_ctrl_handles {
let params = OpenProtocolParams {
handle,
agent: boot::image_handle(),
controller: None,
};
let ata_pt = unsafe {
// don't open exclusive! That would break other tests
boot::open_protocol::<AtaPassThru>(params, OpenProtocolAttributes::GetProtocol).unwrap()
};
for mut device in ata_pt.iter_devices() {
// ATA IDENTIFY command
let request = AtaRequestBuilder::read_udma(ata_pt.io_align(), ATACMD_IDENTIFY)
.unwrap()
.with_timeout(core::time::Duration::from_millis(500))
.with_read_buffer(255)
.unwrap()
.build();
if let Ok(result) = device.execute_command(request) {
let bfr = result.read_buffer().unwrap();
// ATA uses wchar16 big endian strings for serial numbers
let mut serial_bfr = [0u8; 20];
bfr[20..40]
.chunks_exact(2)
.zip(serial_bfr.chunks_exact_mut(2))
.for_each(|(src, dst)| {
dst[0] = src[1];
dst[1] = src[0];
});
let serial = core::str::from_utf8(&serial_bfr).unwrap().trim();
if serial == "AtaPassThru" {
info!("Found Testdisk at handle: {:?}", handle);
return true; // found our testdrive!
}
}
}
}

false
}
8 changes: 8 additions & 0 deletions uefi-test-runner/src/proto/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,15 @@ fn test_partition_info(disk_handle: Handle) {
fn find_test_disk() -> (Handle, ScopedProtocol<SimpleFileSystem>) {
let handles = boot::find_handles::<SimpleFileSystem>()
.expect("Failed to get handles for `SimpleFileSystem` protocol");

// This branch is due to the qemu machine type we use based on the architecture.
// - *Q35* by default uses a SATA-Controller to connect disks.
// - *virt* by default uses virtio to connect disks.
// The aarch64 UEFI Firmware does not yet seem to support SATA-Controllers.
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
assert_eq!(handles.len(), 2);
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
assert_eq!(handles.len(), 3);

for handle in handles {
let mut sfs = boot::open_protocol_exclusive::<SimpleFileSystem>(handle)
Expand Down
7 changes: 7 additions & 0 deletions uefi-test-runner/src/proto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ pub fn test() {
shell_params::test();
string::test();
misc::test();

// disable the ATA test on aarch64 for now. The aarch64 UEFI Firmware does not yet seem
// to support SATA controllers (and providing an AtaPassThru protocol instance for them).
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
ata::test();
scsi::test();
nvme::test();

Expand Down Expand Up @@ -64,6 +69,8 @@ fn test_test_protocol() {
.unwrap());
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ata;
mod console;
mod debug;
mod device_path;
Expand Down
1 change: 1 addition & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Added `proto::device_path::DevicePath::append_node()`.
- Added `proto::scsi::pass_thru::ExtScsiPassThru`.
- Added `proto::nvme::pass_thru::NvmePassThru`.
- Added `proto::ata::pass_thru::AtaPassThru`.

## Changed
- **Breaking:** Removed `BootPolicyError` as `BootPolicy` construction is no
Expand Down
Loading