Skip to content

Commit 8c8eadf

Browse files
authored
Merge pull request #1858 from rust-osdev/handle-convenience
uefi: significantly improve ergonomics of Handle (device path and component2 protocols)
2 parents cf7a4bb + 84e00a3 commit 8c8eadf

File tree

9 files changed

+219
-73
lines changed

9 files changed

+219
-73
lines changed

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ fn test_device_path_to_string() {
107107
let path = create_test_device_path();
108108

109109
let to_text =
110-
|display_only, allow_shortcuts| path.to_string(display_only, allow_shortcuts).unwrap();
110+
|display_only, allow_shortcuts| path.to_string16(display_only, allow_shortcuts).unwrap();
111111

112112
assert_eq!(
113113
&*to_text(DisplayOnly(true), AllowShortcuts(true)),
@@ -167,7 +167,7 @@ fn test_device_path_node_to_string() {
167167
let nodes: Vec<_> = path.node_iter().collect();
168168

169169
let to_text = |node: &DevicePathNode, display_only, allow_shortcuts| {
170-
node.to_string(display_only, allow_shortcuts).unwrap()
170+
node.to_string16(display_only, allow_shortcuts).unwrap()
171171
};
172172

173173
assert_eq!(
@@ -229,20 +229,20 @@ fn test_device_path_append() {
229229
let node = path.node_iter().next().unwrap();
230230

231231
assert_eq!(
232-
path.to_string(DisplayOnly(false), AllowShortcuts(false))
232+
path.to_string16(DisplayOnly(false), AllowShortcuts(false))
233233
.unwrap(),
234234
cstr16!("Ata(Primary,Master,0x1)/VenMsg(E0C14753-F9BE-11D2-9A0C-0090273FC14D)")
235235
);
236236
assert_eq!(
237-
node.to_string(DisplayOnly(false), AllowShortcuts(false))
237+
node.to_string16(DisplayOnly(false), AllowShortcuts(false))
238238
.unwrap(),
239239
cstr16!("Ata(Primary,Master,0x1)")
240240
);
241241

242242
assert_eq!(
243243
path.append_path(&path2)
244244
.unwrap()
245-
.to_string(DisplayOnly(false), AllowShortcuts(false))
245+
.to_string16(DisplayOnly(false), AllowShortcuts(false))
246246
.unwrap(),
247247
cstr16!(
248248
"Ata(Primary,Master,0x1)/VenMsg(E0C14753-F9BE-11D2-9A0C-0090273FC14D)/Ata(Primary,Master,0x1)/VenMsg(E0C14753-F9BE-11D2-9A0C-0090273FC14D)"
@@ -251,7 +251,7 @@ fn test_device_path_append() {
251251
assert_eq!(
252252
path.append_node(node)
253253
.unwrap()
254-
.to_string(DisplayOnly(false), AllowShortcuts(false))
254+
.to_string16(DisplayOnly(false), AllowShortcuts(false))
255255
.unwrap(),
256256
cstr16!(
257257
"Ata(Primary,Master,0x1)/VenMsg(E0C14753-F9BE-11D2-9A0C-0090273FC14D)/Ata(Primary,Master,0x1)"

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

33
use uefi::boot::{self, OpenProtocolParams};
4+
use uefi::proto::device_path::DevicePath;
5+
use uefi::proto::driver::ComponentName2;
46
use uefi::proto::loaded_image::LoadedImage;
57
use uefi::{Identify, proto};
68

@@ -44,6 +46,9 @@ pub fn test() {
4446
shim::test();
4547
shell::test();
4648
tcg::test();
49+
50+
// now test some convenience that combines several things
51+
test_handle_convenience();
4752
}
4853

4954
fn find_protocol() {
@@ -74,6 +79,32 @@ fn test_test_protocol() {
7479
);
7580
}
7681

82+
fn test_handle_convenience() {
83+
// Handles that implement the following protocols:
84+
// - component name 2
85+
// - device path
86+
let handles = {
87+
let mut cn2_handles = boot::find_handles::<ComponentName2>().unwrap();
88+
let dvp_handles = boot::find_handles::<DevicePath>().unwrap();
89+
90+
cn2_handles.retain(|x| dvp_handles.contains(x));
91+
cn2_handles
92+
};
93+
for handle in handles {
94+
let dvp = handle.device_path().expect("should have device path");
95+
let cn2 = handle
96+
.component_name()
97+
.expect("should have component name (v2)");
98+
info!("handle: {:x?}", handle);
99+
info!("|- dvp: {dvp}");
100+
info!("|- cn2 driver: {}", cn2.driver_name("en").unwrap());
101+
info!(
102+
"|- cn2 controller: {}",
103+
cn2.controller_name(handle, None, "en").unwrap()
104+
);
105+
}
106+
}
107+
77108
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
78109
mod ata;
79110
mod console;

uefi-test-runner/src/proto/network/http.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,12 @@
22

33
use alloc::vec::Vec;
44

5-
use uefi::proto::device_path::DevicePath;
6-
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
75
use uefi::proto::network::http::{HttpBinding, HttpHelper};
86
use uefi::proto::network::ip4config2::Ip4Config2;
97
use uefi::{Handle, boot};
108

119
use uefi_raw::protocol::network::http::HttpStatusCode;
1210

13-
pub fn print_handle_devpath(prefix: &str, handle: &Handle) {
14-
let Ok(dp) = boot::open_protocol_exclusive::<DevicePath>(*handle) else {
15-
info!("{prefix}no device path for handle");
16-
return;
17-
};
18-
if let Ok(string) = dp.to_string(DisplayOnly(true), AllowShortcuts(true)) {
19-
info!("{prefix}{string}");
20-
}
21-
}
22-
2311
fn fetch_http(handle: Handle, url: &str) -> Option<Vec<u8>> {
2412
info!("http: fetching {url} ...");
2513

@@ -91,7 +79,7 @@ pub fn test() {
9179
.expect("get nic handles");
9280

9381
for h in handles.as_ref() {
94-
print_handle_devpath("nic: ", h);
82+
info!("nic: {}", h.device_path().expect("should have device path"));
9583

9684
info!("Bring up interface (ip4 config2 protocol)");
9785
let mut ip4 = Ip4Config2::new(*h).expect("open ip4 config2 protocol");

uefi-test-runner/src/proto/nvme/pass_thru.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
use core::time::Duration;
44
use uefi::boot;
5-
use uefi::proto::device_path::DevicePath;
6-
use uefi::proto::device_path::text::{AllowShortcuts, DisplayOnly};
75
use uefi::proto::media::block::BlockIO;
86
use uefi::proto::nvme::pass_thru::NvmePassThru;
97
use uefi::proto::nvme::{NvmeQueueType, NvmeRequestBuilder};
@@ -17,19 +15,14 @@ pub fn test() {
1715
fn has_nvme_drive() -> bool {
1816
let block_io_handles = boot::find_handles::<BlockIO>().unwrap();
1917
for handle in block_io_handles {
20-
let Ok(device_path) = boot::open_protocol_exclusive::<DevicePath>(handle) else {
21-
continue;
22-
};
23-
let mut device_path = &*device_path;
18+
let device_path_proto = handle.device_path().expect("should have device path");
19+
let mut device_path = &*device_path_proto;
2420

2521
let Ok(nvme_pt_handle) = boot::locate_device_path::<NvmePassThru>(&mut device_path) else {
2622
continue;
2723
};
2824
let nvme_pt = boot::open_protocol_exclusive::<NvmePassThru>(nvme_pt_handle).unwrap();
29-
let device_path_str = device_path
30-
.to_string(DisplayOnly(true), AllowShortcuts(false))
31-
.unwrap();
32-
info!("- Successfully opened NVMe: {device_path_str}");
25+
info!("- Successfully opened NVMe: {device_path_proto}");
3326
let mut nvme_ctrl = nvme_pt.controller();
3427

3528
let request = NvmeRequestBuilder::new(nvme_pt.io_align(), 0x06, NvmeQueueType::ADMIN)

uefi-test-runner/src/proto/pci/root_bridge.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn test() {
4545
let subclass_code = ((reg1 >> 16) & 0xFF) as u8;
4646
let device_path = pci_tree.device_path(&root_device_path, addr).unwrap();
4747
let device_path_str = device_path
48-
.to_string(DisplayOnly(false), AllowShortcuts(false))
48+
.to_string16(DisplayOnly(false), AllowShortcuts(false))
4949
.unwrap()
5050
.to_string();
5151

@@ -81,7 +81,7 @@ pub fn test() {
8181
for scsi_handle in scsi_handles {
8282
let device_path = get_open_protocol::<DevicePath>(scsi_handle);
8383
let device_path = device_path
84-
.to_string(DisplayOnly(false), AllowShortcuts(false))
84+
.to_string16(DisplayOnly(false), AllowShortcuts(false))
8585
.unwrap()
8686
.to_string();
8787
assert!(mass_storage_dev_paths.contains(&device_path));

uefi/CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
- Added `proto::device_path::DevicePathUtilities::duplicate_path()`.
1212
- Added `proto::pci::enumeration::PciTree::device_path()`.
1313
- Added `revision()` and `device_type_guid()` to `Serial` protocol
14+
- Implemented `Display` for `DevicePath`, `DevicePathNode` and `ScopedProtocol`,
15+
enabling a easy and convenient way to visualize a device path. For example,
16+
this may print `PciRoot(0x0)/Pci(0x6,0x0)/MAC(525400000001,0x1)`.
17+
`ScopedProtocol` only implements `Display` if the underlying protocol also
18+
implements `Display`.
19+
- Added `Handle::component_name()` and `Handle::device_path()` to simplify the
20+
common use-case of querying more information about a handle.
1421

1522
## Changed
1623
- export all `text::{input, output}::*` types
@@ -28,6 +35,12 @@
2835
- **Breaking:** `boot::check_event` now consumes `&Event` rather than `Event`, removing the
2936
need for unnecessary `Event::unsafe_clone()`s.
3037
- MSRV increased to 1.88.
38+
- **Breaking:** Renamed `DevicePath::to_string()` to `DevicePath::to_string16()`
39+
to better differentiate with the new `to_string()` coming from the new
40+
`Display`.
41+
- **Breaking:** Renamed `DevicePathNode::to_string()` to `DevicePathNode::to_string16()`
42+
to better differentiate with the new `to_string()` coming from the new
43+
`Display`.
3144

3245
# uefi - v0.36.1 (2025-11-05)
3346

uefi/src/boot.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use crate::table::Revision;
4545
use crate::util::opt_nonnull_to_ptr;
4646
use crate::{Char16, Error, Event, Guid, Handle, Result, Status, StatusExt, table};
4747
use core::ffi::c_void;
48+
use core::fmt::{Display, Formatter};
4849
use core::mem::MaybeUninit;
4950
use core::ops::{Deref, DerefMut};
5051
use core::ptr::{self, NonNull};
@@ -1619,6 +1620,20 @@ impl<P: Protocol + ?Sized> ScopedProtocol<P> {
16191620
}
16201621
}
16211622

1623+
// Forward Display impl to inner protocol:
1624+
impl<P: Protocol + ?Sized + Display> Display for ScopedProtocol<P> {
1625+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1626+
match self.get() {
1627+
Some(proto) => {
1628+
write!(f, "{proto}")
1629+
}
1630+
None => {
1631+
write!(f, "<none>")
1632+
}
1633+
}
1634+
}
1635+
}
1636+
16221637
impl<P: Protocol + ?Sized> Drop for ScopedProtocol<P> {
16231638
fn drop(&mut self) {
16241639
let bt = boot_services_raw_panicking();

0 commit comments

Comments
 (0)