Skip to content

Commit 57801aa

Browse files
Add component name protocols
Add support for `EFI_COMPONENT_NAME_PROTOCOL` and `EFI_COMPONENT_NAME2_PROTOCOL`. The former protocol has been deprecated since UEFI 2.1, but there are still some old devices (like some Macbooks) that don't support `EFI_COMPONENT_NAME2_PROTOCOL`. The `ComponentName` wrapper type makes it easy to automatically use the V2 protocol if available, but fall back to V1 otherwise.
1 parent dddbf51 commit 57801aa

File tree

6 files changed

+593
-1
lines changed

6 files changed

+593
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## uefi - [Unreleased]
44

5+
### Added
6+
7+
- Added the `CompnentName1` and `ComponentName2` protocols. The `ComponentName`
8+
wrapper will automatically select `ComponentName2` if available, and fall back
9+
to `ComponentName1` otherwise.
10+
511
### Changed
612

713
- `SystemTable::exit_boot_services` now takes no parameters and handles
@@ -16,7 +22,7 @@
1622

1723
### Added
1824

19-
* Added `table::boot::PAGE_SIZE` constant.
25+
- Added `table::boot::PAGE_SIZE` constant.
2026

2127
### Changed
2228

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

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use uefi::prelude::*;
2+
use uefi::proto::driver::{ComponentName, ComponentName2, LanguageError, LanguageIter};
3+
use uefi::table::boot::{BootServices, ScopedProtocol, SearchType};
4+
use uefi::{CStr16, Result};
5+
6+
#[allow(deprecated)]
7+
use uefi::proto::driver::ComponentName1;
8+
9+
/// Generic interface for testing `ComponentName1`, `ComponentName2`, and
10+
/// `ComponentName`.
11+
trait ComponentNameInterface<'a>: Sized {
12+
fn open(boot_services: &'a BootServices, handle: Handle) -> Result<Self>;
13+
fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError>;
14+
fn driver_name(&self, language: &str) -> Result<&CStr16>;
15+
fn controller_name(
16+
&self,
17+
controller_handle: Handle,
18+
child_handle: Option<Handle>,
19+
language: &str,
20+
) -> Result<&CStr16>;
21+
}
22+
23+
#[allow(deprecated)]
24+
impl<'a> ComponentNameInterface<'a> for ScopedProtocol<'a, ComponentName1> {
25+
fn open(boot_services: &'a BootServices, handle: Handle) -> Result<Self> {
26+
boot_services.open_protocol_exclusive::<ComponentName1>(handle)
27+
}
28+
29+
fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
30+
(**self).supported_languages()
31+
}
32+
33+
fn driver_name(&self, language: &str) -> Result<&CStr16> {
34+
(**self).driver_name(language)
35+
}
36+
37+
fn controller_name(
38+
&self,
39+
controller_handle: Handle,
40+
child_handle: Option<Handle>,
41+
language: &str,
42+
) -> Result<&CStr16> {
43+
(**self).controller_name(controller_handle, child_handle, language)
44+
}
45+
}
46+
47+
impl<'a> ComponentNameInterface<'a> for ScopedProtocol<'a, ComponentName2> {
48+
fn open(boot_services: &'a BootServices, handle: Handle) -> Result<Self> {
49+
boot_services.open_protocol_exclusive::<ComponentName2>(handle)
50+
}
51+
52+
fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
53+
(**self).supported_languages()
54+
}
55+
56+
fn driver_name(&self, language: &str) -> Result<&CStr16> {
57+
(**self).driver_name(language)
58+
}
59+
60+
fn controller_name(
61+
&self,
62+
controller_handle: Handle,
63+
child_handle: Option<Handle>,
64+
language: &str,
65+
) -> Result<&CStr16> {
66+
(**self).controller_name(controller_handle, child_handle, language)
67+
}
68+
}
69+
70+
impl<'a> ComponentNameInterface<'a> for ComponentName<'a> {
71+
fn open(boot_services: &'a BootServices, handle: Handle) -> Result<Self> {
72+
Self::open(boot_services, handle)
73+
}
74+
75+
fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
76+
self.supported_languages()
77+
}
78+
79+
fn driver_name(&self, language: &str) -> Result<&CStr16> {
80+
self.driver_name(language)
81+
}
82+
83+
fn controller_name(
84+
&self,
85+
controller_handle: Handle,
86+
child_handle: Option<Handle>,
87+
language: &str,
88+
) -> Result<&CStr16> {
89+
self.controller_name(controller_handle, child_handle, language)
90+
}
91+
}
92+
93+
fn test_component_name<'a, C: ComponentNameInterface<'a>>(
94+
boot_services: &'a BootServices,
95+
english: &str,
96+
) {
97+
let all_handles = boot_services
98+
.locate_handle_buffer(SearchType::AllHandles)
99+
.unwrap();
100+
101+
let fat_driver_name = cstr16!("FAT File System Driver");
102+
let fat_controller_name = cstr16!("FAT File System");
103+
104+
// Find the FAT driver by name.
105+
let component_name: C = all_handles
106+
.handles()
107+
.iter()
108+
.find_map(|handle| {
109+
let component_name = C::open(boot_services, *handle).ok()?;
110+
111+
assert!(component_name
112+
.supported_languages()
113+
.ok()?
114+
.any(|lang| lang == english));
115+
116+
let driver_name = component_name.driver_name(english).ok()?;
117+
if driver_name == fat_driver_name {
118+
Some(component_name)
119+
} else {
120+
None
121+
}
122+
})
123+
.expect("failed to find FAT driver");
124+
125+
// Now check that the FAT controller can be found by name.
126+
all_handles
127+
.handles()
128+
.iter()
129+
.find(|handle| {
130+
let controller_name = if let Ok(controller_name) =
131+
component_name.controller_name(**handle, None, english)
132+
{
133+
controller_name
134+
} else {
135+
return false;
136+
};
137+
138+
controller_name == fat_controller_name
139+
})
140+
.expect("failed to find FAT controller");
141+
}
142+
143+
pub fn test(boot_services: &BootServices) {
144+
info!("Running component name test");
145+
146+
#[allow(deprecated)]
147+
test_component_name::<ScopedProtocol<ComponentName1>>(boot_services, "eng");
148+
test_component_name::<ScopedProtocol<ComponentName2>>(boot_services, "en");
149+
test_component_name::<ComponentName>(boot_services, "en");
150+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
1414

1515
debug::test(bt);
1616
device_path::test(image, bt);
17+
driver::test(bt);
1718
loaded_image::test(image, bt);
1819
media::test(bt);
1920
network::test(bt);
@@ -61,6 +62,7 @@ fn test_protocols_per_handle(image: Handle, bt: &BootServices) {
6162
mod console;
6263
mod debug;
6364
mod device_path;
65+
mod driver;
6466
mod loaded_image;
6567
mod media;
6668
mod network;

0 commit comments

Comments
 (0)