Skip to content

Commit 0ce684c

Browse files
committed
uefi: Add integration test for ATA_PASS_THRU_PROTOCOL
1 parent 61b36b5 commit 0ce684c

File tree

5 files changed

+96
-0
lines changed

5 files changed

+96
-0
lines changed

Diff for: uefi-test-runner/src/proto/ata/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
mod pass_thru;
4+
5+
pub fn test() {
6+
pass_thru::test();
7+
}

Diff for: uefi-test-runner/src/proto/ata/pass_thru.rs

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
use uefi::boot;
4+
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams};
5+
use uefi::proto::ata::pass_thru::AtaPassThru;
6+
use uefi::proto::ata::AtaRequestBuilder;
7+
8+
pub fn test() {
9+
info!("Running ATA PassThru tests");
10+
11+
assert!(is_testdrive_present());
12+
}
13+
14+
const ATACMD_IDENTIFY: u8 = 0xEC;
15+
16+
fn is_testdrive_present() -> bool {
17+
let ata_ctrl_handles = boot::find_handles::<AtaPassThru>().unwrap();
18+
assert_eq!(ata_ctrl_handles.len(), 1);
19+
20+
for handle in ata_ctrl_handles {
21+
let params = OpenProtocolParams {
22+
handle,
23+
agent: boot::image_handle(),
24+
controller: None,
25+
};
26+
let ata_pt = unsafe {
27+
// don't open exclusive! That would break other tests
28+
boot::open_protocol::<AtaPassThru>(params, OpenProtocolAttributes::GetProtocol).unwrap()
29+
};
30+
for mut device in ata_pt.iter_devices() {
31+
// ATA IDENTIFY command
32+
let request = AtaRequestBuilder::read_udma(ata_pt.io_align(), ATACMD_IDENTIFY)
33+
.unwrap()
34+
.with_timeout(core::time::Duration::from_millis(500))
35+
.with_read_buffer(255)
36+
.unwrap()
37+
.build();
38+
if let Ok(result) = device.execute_command(request) {
39+
let bfr = result.read_buffer().unwrap();
40+
// ATA uses wchar16 big endian strings for serial numbers
41+
let mut serial_bfr = [0u8; 20];
42+
bfr[20..40]
43+
.chunks_exact(2)
44+
.zip(serial_bfr.chunks_exact_mut(2))
45+
.for_each(|(src, dst)| {
46+
dst[0] = src[1];
47+
dst[1] = src[0];
48+
});
49+
let serial = core::str::from_utf8(&serial_bfr).unwrap().trim();
50+
if serial == "AtaPassThru" {
51+
info!("Found Testdisk at handle: {:?}", handle);
52+
return true; // found our testdrive!
53+
}
54+
}
55+
}
56+
}
57+
58+
false
59+
}

Diff for: uefi-test-runner/src/proto/media.rs

+8
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,15 @@ fn test_partition_info(disk_handle: Handle) {
398398
fn find_test_disk() -> (Handle, ScopedProtocol<SimpleFileSystem>) {
399399
let handles = boot::find_handles::<SimpleFileSystem>()
400400
.expect("Failed to get handles for `SimpleFileSystem` protocol");
401+
402+
// This branch is due to the qemu machine type we use based on the architecture.
403+
// - *Q35* by default uses a SATA-Controller to connect disks.
404+
// - *virt* by default uses virtio to connect disks.
405+
// The aarch64 UEFI Firmware does not yet seem to support SATA-Controllers.
406+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
401407
assert_eq!(handles.len(), 2);
408+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
409+
assert_eq!(handles.len(), 3);
402410

403411
for handle in handles {
404412
let mut sfs = boot::open_protocol_exclusive::<SimpleFileSystem>(handle)

Diff for: uefi-test-runner/src/proto/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ pub fn test() {
2525
shell_params::test();
2626
string::test();
2727
misc::test();
28+
29+
// disable the ATA test on aarch64 for now. The aarch64 UEFI Firmware does not yet seem
30+
// to support SATA controllers (and providing an AtaPassThru protocol instance for them).
31+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
32+
ata::test();
2833
scsi::test();
2934
nvme::test();
3035

@@ -64,6 +69,8 @@ fn test_test_protocol() {
6469
.unwrap());
6570
}
6671

72+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
73+
mod ata;
6774
mod console;
6875
mod debug;
6976
mod device_path;

Diff for: xtask/src/qemu.rs

+15
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,11 @@ pub fn run_qemu(arch: UefiArch, opt: &QemuOpt) -> Result<()> {
459459
// Configure SCSI Controller
460460
cmd.arg("-device");
461461
cmd.arg("virtio-scsi-pci");
462+
if arch != UefiArch::IA32 && arch != UefiArch::X86_64 {
463+
// The "virt" qemu machine does not have SATA-Controller by default
464+
cmd.arg("-device");
465+
cmd.arg("ahci,id=ide");
466+
}
462467

463468
// Mount a local directory as a FAT partition.
464469
cmd.arg("-drive");
@@ -499,6 +504,16 @@ pub fn run_qemu(arch: UefiArch, opt: &QemuOpt) -> Result<()> {
499504
cmd.arg("-device");
500505
cmd.arg("nvme,drive=nvmedisk0,serial=uefi-rsNvmePassThru");
501506

507+
// Fifth (ATA) disk
508+
let ata_test_disk = tmp_dir.join("test_disk4.empty.img");
509+
create_mbr_test_disk(&ata_test_disk)?;
510+
cmd.arg("-drive");
511+
let mut drive_arg = OsString::from("if=none,format=raw,id=satadisk0,file=");
512+
drive_arg.push(ata_test_disk.clone());
513+
cmd.arg(drive_arg);
514+
cmd.arg("-device");
515+
cmd.arg("ide-hd,drive=satadisk0,bus=ide.2,serial=AtaPassThru,model=AtaPassThru");
516+
502517
let qemu_monitor_pipe = Pipe::new(tmp_dir, "qemu-monitor")?;
503518
let serial_pipe = Pipe::new(tmp_dir, "serial")?;
504519

0 commit comments

Comments
 (0)