Skip to content

Commit 295ec8d

Browse files
committed
uefi-test-runner: add basic test for blockio protocols
1 parent 593f673 commit 295ec8d

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
//! Very basic tests for the BlockIo and BlockIo2 protocols.
4+
//!
5+
//! We look for some well-known data on a few well-known disks
6+
//! of our test environment.
7+
8+
use alloc::string::String;
9+
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol};
10+
use uefi::proto::Protocol;
11+
use uefi::proto::device_path::DevicePath;
12+
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
13+
use uefi::proto::media::block::{BlockIO, BlockIO2};
14+
use uefi::{CString16, Handle, boot};
15+
use uefi_raw::protocol::device_path::DeviceSubType;
16+
17+
fn verify_block_device(dvp: &DevicePath, first_block: &[u8]) {
18+
// We only look for storage technologies that we are interested in.
19+
let storage_device_types = [
20+
DeviceSubType::MESSAGING_SCSI,
21+
DeviceSubType::MESSAGING_NVME_NAMESPACE,
22+
DeviceSubType::MESSAGING_SATA,
23+
];
24+
let storage_node = dvp
25+
.node_iter()
26+
.skip_while(|x| !storage_device_types.contains(&x.sub_type()))
27+
.next()
28+
.unwrap();
29+
let storage_node_string = storage_node
30+
.to_string(DisplayOnly(true), AllowShortcuts(true))
31+
.unwrap();
32+
debug!("Storage technology: {storage_node_string}");
33+
34+
//debug!("First 512 bytes: {first_block:?}");
35+
match storage_node.sub_type() {
36+
DeviceSubType::MESSAGING_SCSI => { /* empty disks so far, nothing to check for */ }
37+
DeviceSubType::MESSAGING_NVME_NAMESPACE => {
38+
/* empty disks so far, nothing to check for */
39+
}
40+
DeviceSubType::MESSAGING_SATA => {
41+
// We check that the right SATA disk indeed contains a correct
42+
// FAT16 volume.
43+
let expected = "MbrTestDisk";
44+
let contains_volume_label = first_block
45+
.windows(expected.len())
46+
.any(|w| w == expected.as_bytes());
47+
let oem_name = {
48+
let bytes = &first_block[3..10];
49+
String::from_utf8(bytes.to_vec())
50+
};
51+
let is_valid_fat = first_block[0] != 0 && oem_name.is_ok();
52+
if is_valid_fat && storage_node.data() == &[0x2, 0, 0xff, 0xff, 0x0, 0x0] {
53+
if !contains_volume_label {
54+
panic!(
55+
"Sata disk {storage_node_string} does not contain {expected} in its first 512 bytes"
56+
)
57+
} else {
58+
debug!(
59+
"Found volume label {expected} with OEM name: {}",
60+
oem_name.unwrap()
61+
);
62+
}
63+
}
64+
}
65+
_ => unreachable!(),
66+
}
67+
}
68+
69+
fn open_proto_and_dvp<P: Protocol>(
70+
handle: Handle,
71+
) -> (ScopedProtocol<P>, ScopedProtocol<DevicePath>, CString16) {
72+
let proto = unsafe {
73+
boot::open_protocol::<P>(
74+
OpenProtocolParams {
75+
handle,
76+
agent: boot::image_handle(),
77+
controller: None,
78+
},
79+
OpenProtocolAttributes::GetProtocol,
80+
)
81+
.unwrap()
82+
};
83+
let dvp = unsafe {
84+
boot::open_protocol::<DevicePath>(
85+
OpenProtocolParams {
86+
handle,
87+
agent: boot::image_handle(),
88+
controller: None,
89+
},
90+
OpenProtocolAttributes::GetProtocol,
91+
)
92+
.unwrap()
93+
};
94+
let dvp_string = dvp
95+
.to_string(DisplayOnly(true), AllowShortcuts(true))
96+
.unwrap();
97+
98+
(proto, dvp, dvp_string)
99+
}
100+
101+
fn test_blockio_protocol() {
102+
info!("Testing BLOCKIO protocol");
103+
for handle in boot::find_handles::<BlockIO>().unwrap() {
104+
let (proto, dvp, dvp_string) = open_proto_and_dvp::<BlockIO>(handle);
105+
debug!("Found handle supporting protocol: {dvp_string}");
106+
debug!("media: {:?}", proto.media());
107+
let mut first_block = vec![0; 512];
108+
proto
109+
.read_blocks(proto.media().media_id(), 0, &mut first_block)
110+
.unwrap();
111+
112+
verify_block_device(&dvp, first_block.as_slice());
113+
}
114+
}
115+
116+
fn test_blockio2_protocol() {
117+
info!("Testing BLOCKIO 2 protocol");
118+
119+
for handle in boot::find_handles::<BlockIO2>().unwrap() {
120+
let (proto, dvp, dvp_string) = open_proto_and_dvp::<BlockIO2>(handle);
121+
debug!("Found handle supporting protocol: {dvp_string}");
122+
debug!("media: {:?}", proto.media());
123+
let mut first_block = vec![0; 512];
124+
unsafe {
125+
proto
126+
.read_blocks_ex(proto.media().media_id(), 0, None, &mut first_block)
127+
.unwrap();
128+
}
129+
130+
verify_block_device(&dvp, first_block.as_slice());
131+
}
132+
}
133+
134+
pub fn test() {
135+
test_blockio_protocol();
136+
test_blockio2_protocol();
137+
}

uefi-test-runner/src/proto/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ pub fn test() {
99

1010
console::test();
1111

12-
find_protocol();
12+
test_find_handles();
1313
test_protocols_per_handle();
1414
test_test_protocol();
1515

16+
block::test();
1617
debug::test();
1718
device_path::test();
1819
driver::test();
@@ -46,7 +47,11 @@ pub fn test() {
4647
tcg::test();
4748
}
4849

49-
fn find_protocol() {
50+
/// Tests that the [`boot::find_handles`] wrapper can find handles using the
51+
/// [`Output`] protocol.
52+
///
53+
/// [`Output`]: proto::console::text::Output
54+
fn test_find_handles() {
5055
let handles = boot::find_handles::<proto::console::text::Output>()
5156
.expect("Failed to retrieve list of handles");
5257

@@ -76,6 +81,7 @@ fn test_test_protocol() {
7681

7782
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
7883
mod ata;
84+
mod block;
7985
mod console;
8086
mod debug;
8187
mod device_path;

0 commit comments

Comments
 (0)