@@ -216,6 +216,60 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
216216 Err ( io:: const_error!( io:: ErrorKind :: NotFound , "no device path to text protocol found" ) )
217217}
218218
219+ fn device_node_to_text ( path : NonNull < device_path:: Protocol > ) -> io:: Result < OsString > {
220+ fn node_to_text (
221+ protocol : NonNull < device_path_to_text:: Protocol > ,
222+ path : NonNull < device_path:: Protocol > ,
223+ ) -> io:: Result < OsString > {
224+ let path_ptr: * mut r_efi:: efi:: Char16 = unsafe {
225+ ( ( * protocol. as_ptr ( ) ) . convert_device_node_to_text ) (
226+ path. as_ptr ( ) ,
227+ // DisplayOnly
228+ r_efi:: efi:: Boolean :: FALSE ,
229+ // AllowShortcuts
230+ r_efi:: efi:: Boolean :: FALSE ,
231+ )
232+ } ;
233+
234+ let path = os_string_from_raw ( path_ptr)
235+ . ok_or ( io:: const_error!( io:: ErrorKind :: InvalidData , "Invalid path" ) ) ?;
236+
237+ if let Some ( boot_services) = crate :: os:: uefi:: env:: boot_services ( ) {
238+ let boot_services: NonNull < r_efi:: efi:: BootServices > = boot_services. cast ( ) ;
239+ unsafe {
240+ ( ( * boot_services. as_ptr ( ) ) . free_pool ) ( path_ptr. cast ( ) ) ;
241+ }
242+ }
243+
244+ Ok ( path)
245+ }
246+
247+ static LAST_VALID_HANDLE : AtomicPtr < crate :: ffi:: c_void > =
248+ AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ;
249+
250+ if let Some ( handle) = NonNull :: new ( LAST_VALID_HANDLE . load ( Ordering :: Acquire ) ) {
251+ if let Ok ( protocol) = open_protocol :: < device_path_to_text:: Protocol > (
252+ handle,
253+ device_path_to_text:: PROTOCOL_GUID ,
254+ ) {
255+ return node_to_text ( protocol, path) ;
256+ }
257+ }
258+
259+ let device_path_to_text_handles = locate_handles ( device_path_to_text:: PROTOCOL_GUID ) ?;
260+ for handle in device_path_to_text_handles {
261+ if let Ok ( protocol) = open_protocol :: < device_path_to_text:: Protocol > (
262+ handle,
263+ device_path_to_text:: PROTOCOL_GUID ,
264+ ) {
265+ LAST_VALID_HANDLE . store ( handle. as_ptr ( ) , Ordering :: Release ) ;
266+ return node_to_text ( protocol, path) ;
267+ }
268+ }
269+
270+ Err ( io:: const_error!( io:: ErrorKind :: NotFound , "No device path to text protocol found" ) )
271+ }
272+
219273/// Gets RuntimeServices.
220274pub ( crate ) fn runtime_services ( ) -> Option < NonNull < r_efi:: efi:: RuntimeServices > > {
221275 let system_table: NonNull < r_efi:: efi:: SystemTable > =
@@ -319,6 +373,11 @@ impl<'a> BorrowedDevicePath<'a> {
319373 pub ( crate ) fn to_text ( & self ) -> io:: Result < OsString > {
320374 device_path_to_text ( self . protocol )
321375 }
376+
377+ #[ expect( dead_code) ]
378+ pub ( crate ) const fn iter ( & ' a self ) -> DevicePathIterator < ' a > {
379+ DevicePathIterator :: new ( DevicePathNode :: new ( self . protocol ) )
380+ }
322381}
323382
324383impl < ' a > crate :: fmt:: Debug for BorrowedDevicePath < ' a > {
@@ -330,6 +389,126 @@ impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> {
330389 }
331390}
332391
392+ pub ( crate ) struct DevicePathIterator < ' a > ( Option < DevicePathNode < ' a > > ) ;
393+
394+ impl < ' a > DevicePathIterator < ' a > {
395+ const fn new ( node : DevicePathNode < ' a > ) -> Self {
396+ if node. is_end ( ) { Self ( None ) } else { Self ( Some ( node) ) }
397+ }
398+ }
399+
400+ impl < ' a > Iterator for DevicePathIterator < ' a > {
401+ type Item = DevicePathNode < ' a > ;
402+
403+ fn next ( & mut self ) -> Option < Self :: Item > {
404+ let cur_node = self . 0 ?;
405+
406+ let next_node = unsafe { cur_node. next_node ( ) } ;
407+ self . 0 = if next_node. is_end ( ) { None } else { Some ( next_node) } ;
408+
409+ Some ( cur_node)
410+ }
411+ }
412+
413+ #[ derive( Copy , Clone ) ]
414+ pub ( crate ) struct DevicePathNode < ' a > {
415+ protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ,
416+ phantom : PhantomData < & ' a r_efi:: protocols:: device_path:: Protocol > ,
417+ }
418+
419+ impl < ' a > DevicePathNode < ' a > {
420+ pub ( crate ) const fn new ( protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ) -> Self {
421+ Self { protocol, phantom : PhantomData }
422+ }
423+
424+ pub ( crate ) const fn length ( & self ) -> u16 {
425+ let len = unsafe { ( * self . protocol . as_ptr ( ) ) . length } ;
426+ u16:: from_le_bytes ( len)
427+ }
428+
429+ pub ( crate ) const fn node_type ( & self ) -> u8 {
430+ unsafe { ( * self . protocol . as_ptr ( ) ) . r#type }
431+ }
432+
433+ pub ( crate ) const fn sub_type ( & self ) -> u8 {
434+ unsafe { ( * self . protocol . as_ptr ( ) ) . sub_type }
435+ }
436+
437+ pub ( crate ) fn data ( & self ) -> & [ u8 ] {
438+ let length: usize = self . length ( ) . into ( ) ;
439+
440+ // Some nodes do not have any special data
441+ if length > 4 {
442+ let raw_ptr: * const u8 = self . protocol . as_ptr ( ) . cast ( ) ;
443+ let data = unsafe { raw_ptr. add ( 4 ) } ;
444+ unsafe { crate :: slice:: from_raw_parts ( data, length - 4 ) }
445+ } else {
446+ & [ ]
447+ }
448+ }
449+
450+ pub ( crate ) const fn is_end ( & self ) -> bool {
451+ self . node_type ( ) == r_efi:: protocols:: device_path:: TYPE_END
452+ && self . sub_type ( ) == r_efi:: protocols:: device_path:: End :: SUBTYPE_ENTIRE
453+ }
454+
455+ #[ expect( dead_code) ]
456+ pub ( crate ) const fn is_end_instance ( & self ) -> bool {
457+ self . node_type ( ) == r_efi:: protocols:: device_path:: TYPE_END
458+ && self . sub_type ( ) == r_efi:: protocols:: device_path:: End :: SUBTYPE_INSTANCE
459+ }
460+
461+ pub ( crate ) unsafe fn next_node ( & self ) -> Self {
462+ let node = unsafe {
463+ self . protocol
464+ . cast :: < u8 > ( )
465+ . add ( self . length ( ) . into ( ) )
466+ . cast :: < r_efi:: protocols:: device_path:: Protocol > ( )
467+ } ;
468+ Self :: new ( node)
469+ }
470+
471+ #[ expect( dead_code) ]
472+ pub ( crate ) fn to_path ( & ' a self ) -> BorrowedDevicePath < ' a > {
473+ BorrowedDevicePath :: new ( self . protocol )
474+ }
475+
476+ pub ( crate ) fn to_text ( & self ) -> io:: Result < OsString > {
477+ device_node_to_text ( self . protocol )
478+ }
479+ }
480+
481+ impl < ' a > PartialEq for DevicePathNode < ' a > {
482+ fn eq ( & self , other : & Self ) -> bool {
483+ let self_len = self . length ( ) ;
484+ let other_len = other. length ( ) ;
485+
486+ self_len == other_len
487+ && unsafe {
488+ compiler_builtins:: mem:: memcmp (
489+ self . protocol . as_ptr ( ) . cast ( ) ,
490+ other. protocol . as_ptr ( ) . cast ( ) ,
491+ usize:: from ( self_len) ,
492+ ) == 0
493+ }
494+ }
495+ }
496+
497+ impl < ' a > crate :: fmt:: Debug for DevicePathNode < ' a > {
498+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
499+ match self . to_text ( ) {
500+ Ok ( p) => p. fmt ( f) ,
501+ Err ( _) => f
502+ . debug_struct ( "DevicePathNode" )
503+ . field ( "type" , & self . node_type ( ) )
504+ . field ( "sub_type" , & self . sub_type ( ) )
505+ . field ( "length" , & self . length ( ) )
506+ . field ( "specific_device_path_data" , & self . data ( ) )
507+ . finish ( ) ,
508+ }
509+ }
510+ }
511+
333512pub ( crate ) struct OwnedProtocol < T > {
334513 guid : r_efi:: efi:: Guid ,
335514 handle : NonNull < crate :: ffi:: c_void > ,
0 commit comments