@@ -17,6 +17,7 @@ mod section_decompress;
1717use alloc:: {
1818 boxed:: Box ,
1919 collections:: { BTreeMap , BTreeSet } ,
20+ string:: { String , ToString } ,
2021 vec:: Vec ,
2122} ;
2223use 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