Skip to content

Commit af131ee

Browse files
committed
pi_dispatcher: Add UI Names to Prints
Currently when various states occur, such as drivers not dispatched, only the GUID of the driver is printed. This is useful, but also it is nicer to have the UI name printed so the GUID does not have to be cross-referenced. This parses the UI name from the FV, if present, and also prints it.
1 parent 705728d commit af131ee

1 file changed

Lines changed: 114 additions & 4 deletions

File tree

patina_dxe_core/src/pi_dispatcher.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod section_decompress;
1717
use alloc::{
1818
boxed::Box,
1919
collections::{BTreeMap, BTreeSet},
20+
string::{String, ToString},
2021
vec::Vec,
2122
};
2223
use core::{cmp::Ordering, ffi::c_void};
@@ -105,7 +106,11 @@ impl<P: PlatformInfo> PiDispatcher<P> {
105106
/// Displays drivers that were discovered but not dispatched.
106107
pub fn display_discovered_not_dispatched(&self) {
107108
for driver in &self.dispatcher_context.lock().pending_drivers {
108-
log::warn!("Driver {:?} found but not dispatched.", guid_fmt!(driver.file_name));
109+
log::warn!(
110+
"Driver {} ({:?}) found but not dispatched.",
111+
driver.name.as_deref().unwrap_or("Unnamed"),
112+
guid_fmt!(driver.file_name)
113+
);
109114
}
110115
}
111116

@@ -231,7 +236,7 @@ impl<P: PlatformInfo> PiDispatcher<P> {
231236
let driver_candidates: Vec<_> = dispatcher.pending_drivers.drain(..).collect();
232237
let mut scheduled_driver_candidates = Vec::new();
233238
for mut candidate in driver_candidates {
234-
log::debug!(target: "patina_internal_depex", "Evaluating depex for candidate: {:?}", guid_fmt!(candidate.file_name));
239+
log::debug!(target: "patina_internal_depex", "Evaluating depex for candidate: {} ({:?})", candidate.name.as_deref().unwrap_or("Unnamed"), guid_fmt!(candidate.file_name));
235240
let depex_satisfied = match candidate.depex {
236241
Some(ref mut depex) => depex.eval(&PROTOCOL_DB.registered_protocols()),
237242
None => dispatcher.arch_protocols_available,
@@ -299,15 +304,17 @@ impl<P: PlatformInfo> PiDispatcher<P> {
299304
}
300305
efi::Status::SECURITY_VIOLATION => {
301306
log::info!(
302-
"Deferring driver: {:?} due to security status: {:x?}",
307+
"Deferring driver: {} ({:?}) due to security status: {:x?}",
308+
driver.name.as_deref().unwrap_or("Unnamed"),
303309
guid_fmt!(driver.file_name),
304310
efi::Status::SECURITY_VIOLATION
305311
);
306312
self.dispatcher_context.lock().pending_drivers.push(driver);
307313
}
308314
unexpected_status => {
309315
log::info!(
310-
"Dropping driver: {:?} due to security status: {:x?}",
316+
"Dropping driver: {} ({:?}) due to security status: {:x?}",
317+
driver.name.as_deref().unwrap_or("Unnamed"),
311318
guid_fmt!(driver.file_name),
312319
unexpected_status
313320
);
@@ -504,6 +511,7 @@ struct PendingDriver {
504511
firmware_volume_handle: efi::Handle,
505512
device_path: *mut efi::protocols::device_path::Protocol,
506513
file_name: efi::Guid,
514+
name: Option<String>,
507515
depex: Option<Depex>,
508516
pe32: Section,
509517
image_handle: Option<efi::Handle>,
@@ -662,6 +670,16 @@ impl DispatcherContext {
662670
.transpose()?
663671
.map(Depex::from);
664672

673+
let name = sections
674+
.iter()
675+
.find(|x| x.section_type() == Some(ffs::section::Type::UserInterface))
676+
.and_then(|x| x.try_content_as_slice().ok())
677+
.map(|data| {
678+
let chars: Vec<u16> =
679+
data.chunks_exact(2).map(|c| u16::from_le_bytes([c[0], c[1]])).collect();
680+
String::from_utf16_lossy(&chars).trim_end_matches('\0').to_string()
681+
});
682+
665683
if let Some(pe32_section) =
666684
sections.into_iter().find(|x| x.section_type() == Some(ffs::section::Type::Pe32))
667685
{
@@ -717,6 +735,7 @@ impl DispatcherContext {
717735

718736
self.pending_drivers.push(PendingDriver {
719737
file_name,
738+
name,
720739
firmware_volume_handle: handle,
721740
pe32: pe32_section,
722741
device_path: full_device_path_for_file,
@@ -1730,6 +1749,97 @@ mod tests {
17301749
});
17311750
}
17321751

1752+
#[test]
1753+
fn test_display_discovered_not_dispatched_with_named_driver() {
1754+
with_locked_state(|| {
1755+
use patina_ffs::section::SectionHeader;
1756+
1757+
static CORE: MockCore = MockCore::new(NullSectionExtractor::new());
1758+
CORE.override_instance();
1759+
1760+
// Build a minimal PE32 section (content doesn't matter for this test).
1761+
let pe32_header = SectionHeader::Standard(ffs::section::raw_type::PE32, 4);
1762+
let pe32_section = Section::new_from_header_with_data(pe32_header, vec![0u8; 4]).expect("PE32 section");
1763+
1764+
let test_guid =
1765+
efi::Guid::from_fields(0xAABBCCDD, 0x1122, 0x3344, 0x55, 0x66, &[0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC]);
1766+
1767+
// Driver with a UI name.
1768+
CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers.push(PendingDriver {
1769+
firmware_volume_handle: std::ptr::null_mut(),
1770+
device_path: std::ptr::null_mut(),
1771+
file_name: test_guid,
1772+
name: Some(String::from("TestDriver")),
1773+
depex: None,
1774+
pe32: pe32_section,
1775+
image_handle: None,
1776+
security_status: efi::Status::NOT_READY,
1777+
});
1778+
1779+
// Build another PE32 section for the unnamed driver.
1780+
let pe32_header2 = SectionHeader::Standard(ffs::section::raw_type::PE32, 4);
1781+
let pe32_section2 = Section::new_from_header_with_data(pe32_header2, vec![0u8; 4]).expect("PE32 section");
1782+
1783+
// Driver without a UI name.
1784+
CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers.push(PendingDriver {
1785+
firmware_volume_handle: std::ptr::null_mut(),
1786+
device_path: std::ptr::null_mut(),
1787+
file_name: test_guid,
1788+
name: None,
1789+
depex: None,
1790+
pe32: pe32_section2,
1791+
image_handle: None,
1792+
security_status: efi::Status::NOT_READY,
1793+
});
1794+
1795+
assert_eq!(CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers.len(), 2);
1796+
assert_eq!(
1797+
CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers[0].name.as_deref(),
1798+
Some("TestDriver")
1799+
);
1800+
assert!(CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers[1].name.is_none());
1801+
1802+
// Verify display doesn't panic for both named and unnamed drivers.
1803+
CORE.pi_dispatcher.display_discovered_not_dispatched();
1804+
});
1805+
}
1806+
1807+
#[test]
1808+
fn test_display_discovered_not_dispatched_parses_ui_name_from_fv() {
1809+
let mut file = File::open(test_collateral!("DXEFV.Fv")).unwrap();
1810+
let mut fv: Vec<u8> = Vec::new();
1811+
file.read_to_end(&mut fv).expect("failed to read test file");
1812+
let fv = fv.into_boxed_slice();
1813+
let fv_raw = Box::into_raw(fv);
1814+
1815+
with_locked_state(|| {
1816+
static CORE: MockCore = MockCore::new(NullSectionExtractor::new());
1817+
CORE.override_instance();
1818+
1819+
// SAFETY: fv_raw points to a valid boxed slice that outlives this closure.
1820+
let handle = unsafe {
1821+
CORE.pi_dispatcher
1822+
.fv_data
1823+
.lock()
1824+
.install_firmware_volume(fv_raw.expose_provenance() as u64, None)
1825+
.unwrap()
1826+
};
1827+
1828+
CORE.pi_dispatcher.add_fv_handles(vec![handle]).expect("Failed to add FV handle");
1829+
1830+
let has_named =
1831+
CORE.pi_dispatcher.dispatcher_context.lock().pending_drivers.iter().any(|d| d.name.is_some());
1832+
// At least one driver in the test FV should have a UI name section.
1833+
assert!(has_named, "Expected at least one driver with a parsed UI name");
1834+
1835+
// Verify display doesn't panic with a mix of named/unnamed drivers.
1836+
CORE.pi_dispatcher.display_discovered_not_dispatched();
1837+
});
1838+
1839+
// SAFETY: fv_raw was created from Box::into_raw and is dropped only once here.
1840+
let _dropped_fv = unsafe { Box::from_raw(fv_raw) };
1841+
}
1842+
17331843
#[test]
17341844
fn test_dispatch_with_corrupted_fv_section() {
17351845
set_logger();

0 commit comments

Comments
 (0)