Skip to content

Commit 2844372

Browse files
committed
uefi: Implement safe bindings for EFI_ATA_PASS_THRU_PROTOCOL
1 parent 6ab3d14 commit 2844372

File tree

10 files changed

+708
-27
lines changed

10 files changed

+708
-27
lines changed

Diff for: uefi-raw/src/protocol/ata.rs

+29-27
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ bitflags::bitflags! {
3131
}
3232
}
3333

34-
#[derive(Debug)]
34+
#[derive(Clone, Debug)]
3535
#[repr(C)]
3636
pub struct AtaPassThruMode {
3737
pub attributes: AtaPassThruAttributes,
@@ -76,37 +76,37 @@ newtype_enum! {
7676
#[repr(C)]
7777
pub struct AtaStatusBlock {
7878
pub reserved1: [u8; 2],
79-
pub ata_status: u8,
80-
pub ata_error: u8,
81-
pub ata_sector_number: u8,
82-
pub ata_cylinder_low: u8,
83-
pub ata_cylinder_high: u8,
84-
pub ata_device_head: u8,
85-
pub ata_sector_number_exp: u8,
86-
pub ata_cylinder_low_exp: u8,
87-
pub ata_cylinder_high_exp: u8,
79+
pub status: u8,
80+
pub error: u8,
81+
pub sector_number: u8,
82+
pub cylinder_low: u8,
83+
pub cylinder_high: u8,
84+
pub device_head: u8,
85+
pub sector_number_exp: u8,
86+
pub cylinder_low_exp: u8,
87+
pub cylinder_high_exp: u8,
8888
pub reserved2: u8,
89-
pub ata_sector_count: u8,
90-
pub ata_sector_count_exp: u8,
89+
pub sector_count: u8,
90+
pub sector_count_exp: u8,
9191
pub reserved3: [u8; 6],
9292
}
9393

94-
#[derive(Debug)]
94+
#[derive(Debug, Default)]
9595
#[repr(C)]
9696
pub struct AtaCommandBlock {
9797
pub reserved1: [u8; 2],
98-
pub ata_command: u8,
99-
pub ata_features: u8,
100-
pub ata_sector_number: u8,
101-
pub ata_cylinder_low: u8,
102-
pub ata_cylinder_high: u8,
103-
pub ata_device_head: u8,
104-
pub ata_sector_number_exp: u8,
105-
pub ata_cylinder_low_exp: u8,
106-
pub ata_cylinder_high_exp: u8,
107-
pub ata_features_exp: u8,
108-
pub ata_sector_count: u8,
109-
pub ata_sector_count_exp: u8,
98+
pub command: u8,
99+
pub features: u8,
100+
pub sector_number: u8,
101+
pub cylinder_low: u8,
102+
pub cylinder_high: u8,
103+
pub device_head: u8,
104+
pub sector_number_exp: u8,
105+
pub cylinder_low_exp: u8,
106+
pub cylinder_high_exp: u8,
107+
pub features_exp: u8,
108+
pub sector_count: u8,
109+
pub sector_count_exp: u8,
110110
pub reserved2: [u8; 6],
111111
}
112112

@@ -118,6 +118,8 @@ pub struct AtaPassThruCommandPacket {
118118
pub timeout: u64,
119119
pub in_data_buffer: *mut c_void,
120120
pub out_data_buffer: *const c_void,
121+
pub in_transfer_length: u32,
122+
pub out_transfer_length: u32,
121123
pub protocol: AtaPassThruCommandProtocol,
122124
pub length: AtaPassThruLength,
123125
}
@@ -131,7 +133,7 @@ pub struct AtaPassThruProtocol {
131133
port: u16,
132134
port_multiplier_port: u16,
133135
packet: *mut AtaPassThruCommandPacket,
134-
event: *mut Event,
136+
event: Event,
135137
) -> Status,
136138
pub get_next_port: unsafe extern "efiapi" fn(this: *const Self, port: *mut u16) -> Status,
137139
pub get_next_device: unsafe extern "efiapi" fn(
@@ -143,7 +145,7 @@ pub struct AtaPassThruProtocol {
143145
this: *const Self,
144146
port: u16,
145147
port_multiplier_port: u16,
146-
device_path: *mut *mut DevicePathProtocol,
148+
device_path: *mut *const DevicePathProtocol,
147149
) -> Status,
148150
pub get_device: unsafe extern "efiapi" fn(
149151
this: *const Self,

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+
// what the...
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

+4
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,11 @@ 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+
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
401403
assert_eq!(handles.len(), 2);
404+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
405+
assert_eq!(handles.len(), 3);
402406

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

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

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ pub fn test() {
1313
test_protocols_per_handle();
1414
test_test_protocol();
1515

16+
// disable the ATA test on aarch64 for now. The aarch64 UEFI Firmware does not yet seem
17+
// to support SATA controllers (and providing an AtaPassThru protocol instance for them).
18+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
19+
ata::test();
1620
debug::test();
1721
device_path::test();
1822
driver::test();
@@ -62,6 +66,8 @@ fn test_test_protocol() {
6266
.unwrap());
6367
}
6468

69+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
70+
mod ata;
6571
mod console;
6672
mod debug;
6773
mod device_path;

Diff for: uefi/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Added `mem::AlignedBuffer`.
99
- Added `proto::device_path::DevicePath::append_path()`.
1010
- Added `proto::device_path::DevicePath::append_node()`.
11+
- Added `proto::ata::pass_thru::AtaPassThru`.
1112

1213
## Changed
1314
- **Breaking:** Removed `BootPolicyError` as `BootPolicy` construction is no

0 commit comments

Comments
 (0)