@@ -14,6 +14,8 @@ use r_efi::protocols::{device_path, device_path_to_text, shell};
1414
1515use crate :: ffi:: { OsStr , OsString } ;
1616use crate :: io:: { self , const_error} ;
17+ use crate :: iter:: Iterator ;
18+ use crate :: marker:: PhantomData ;
1719use crate :: mem:: { MaybeUninit , size_of} ;
1820use crate :: os:: uefi:: env:: boot_services;
1921use crate :: os:: uefi:: ffi:: { OsStrExt , OsStringExt } ;
@@ -214,6 +216,60 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
214216 Err ( io:: const_error!( io:: ErrorKind :: NotFound , "No device path to text protocol found" ) )
215217}
216218
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+
217273/// Gets RuntimeServices.
218274pub ( crate ) fn runtime_services ( ) -> Option < NonNull < r_efi:: efi:: RuntimeServices > > {
219275 let system_table: NonNull < r_efi:: efi:: SystemTable > =
@@ -278,6 +334,10 @@ impl OwnedDevicePath {
278334 pub ( crate ) const fn as_ptr ( & self ) -> * mut r_efi:: protocols:: device_path:: Protocol {
279335 self . 0 . as_ptr ( )
280336 }
337+
338+ pub ( crate ) const fn borrow < ' a > ( & ' a self ) -> BorrowedDevicePath < ' a > {
339+ BorrowedDevicePath :: new ( self . 0 )
340+ }
281341}
282342
283343impl Drop for OwnedDevicePath {
@@ -293,8 +353,140 @@ impl Drop for OwnedDevicePath {
293353
294354impl crate :: fmt:: Debug for OwnedDevicePath {
295355 fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
296- let p = device_path_to_text ( self . 0 ) . unwrap ( ) ;
297- p. fmt ( f)
356+ self . borrow ( ) . fmt ( f)
357+ }
358+ }
359+
360+ pub ( crate ) struct BorrowedDevicePath < ' a > {
361+ protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ,
362+ phantom : PhantomData < & ' a r_efi:: protocols:: device_path:: Protocol > ,
363+ }
364+
365+ impl < ' a > BorrowedDevicePath < ' a > {
366+ pub ( crate ) const fn new ( protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ) -> Self {
367+ Self { protocol, phantom : PhantomData }
368+ }
369+
370+ pub ( crate ) const fn iter ( & ' a self ) -> DevicePathIterator < ' a > {
371+ DevicePathIterator :: new ( DevicePathNode :: new ( self . protocol ) )
372+ }
373+
374+ pub ( crate ) fn to_text ( & self ) -> io:: Result < OsString > {
375+ device_path_to_text ( self . protocol )
376+ }
377+ }
378+
379+ impl < ' a > crate :: fmt:: Debug for BorrowedDevicePath < ' a > {
380+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
381+ match self . to_text ( ) {
382+ Ok ( p) => p. fmt ( f) ,
383+ Err ( _) => f. debug_list ( ) . entries ( self . iter ( ) ) . finish ( ) ,
384+ }
385+ }
386+ }
387+
388+ pub ( crate ) struct DevicePathIterator < ' a > ( Option < DevicePathNode < ' a > > ) ;
389+
390+ impl < ' a > DevicePathIterator < ' a > {
391+ const fn new ( node : DevicePathNode < ' a > ) -> Self {
392+ if node. is_end ( ) { Self ( None ) } else { Self ( Some ( node) ) }
393+ }
394+ }
395+
396+ impl < ' a > Iterator for DevicePathIterator < ' a > {
397+ type Item = DevicePathNode < ' a > ;
398+
399+ fn next ( & mut self ) -> Option < Self :: Item > {
400+ let cur_node = self . 0 ?;
401+
402+ let next_node = unsafe { cur_node. next_node ( ) } ;
403+ self . 0 = if next_node. is_end ( ) { None } else { Some ( next_node) } ;
404+
405+ Some ( cur_node)
406+ }
407+ }
408+
409+ #[ derive( Copy , Clone ) ]
410+ pub ( crate ) struct DevicePathNode < ' a > {
411+ protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ,
412+ phantom : PhantomData < & ' a r_efi:: protocols:: device_path:: Protocol > ,
413+ }
414+
415+ impl < ' a > DevicePathNode < ' a > {
416+ pub ( crate ) const fn new ( protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ) -> Self {
417+ Self { protocol, phantom : PhantomData }
418+ }
419+
420+ pub ( crate ) const fn length ( & self ) -> u16 {
421+ let len = unsafe { ( * self . protocol . as_ptr ( ) ) . length } ;
422+ u16:: from_le_bytes ( len)
423+ }
424+
425+ pub ( crate ) const fn node_type ( & self ) -> u8 {
426+ unsafe { ( * self . protocol . as_ptr ( ) ) . r#type }
427+ }
428+
429+ pub ( crate ) const fn sub_type ( & self ) -> u8 {
430+ unsafe { ( * self . protocol . as_ptr ( ) ) . sub_type }
431+ }
432+
433+ pub ( crate ) const fn data ( & self ) -> & [ u8 ] {
434+ let length = self . length ( ) as usize ;
435+
436+ // Some nodes do not have any special data
437+ if length > 4 {
438+ let raw_ptr: * const u8 = self . protocol . as_ptr ( ) . cast ( ) ;
439+ let data = unsafe { raw_ptr. add ( 4 ) } ;
440+ unsafe { crate :: slice:: from_raw_parts ( data, length - 4 ) }
441+ } else {
442+ & [ ]
443+ }
444+ }
445+
446+ pub ( crate ) const fn is_end ( & self ) -> bool {
447+ self . node_type ( ) == r_efi:: protocols:: device_path:: TYPE_END
448+ && self . sub_type ( ) == r_efi:: protocols:: device_path:: End :: SUBTYPE_ENTIRE
449+ }
450+
451+ pub ( crate ) unsafe fn next_node ( & self ) -> Self {
452+ let node = unsafe {
453+ self . protocol
454+ . cast :: < u8 > ( )
455+ . add ( self . length ( ) . into ( ) )
456+ . cast :: < r_efi:: protocols:: device_path:: Protocol > ( )
457+ } ;
458+ Self :: new ( node)
459+ }
460+ }
461+
462+ impl < ' a > PartialEq for DevicePathNode < ' a > {
463+ fn eq ( & self , other : & Self ) -> bool {
464+ let self_len = self . length ( ) ;
465+ let other_len = other. length ( ) ;
466+
467+ self_len == other_len
468+ && unsafe {
469+ compiler_builtins:: mem:: memcmp (
470+ self . protocol . as_ptr ( ) . cast ( ) ,
471+ other. protocol . as_ptr ( ) . cast ( ) ,
472+ usize:: from ( self_len) ,
473+ ) == 0
474+ }
475+ }
476+ }
477+
478+ impl < ' a > crate :: fmt:: Debug for DevicePathNode < ' a > {
479+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
480+ match device_node_to_text ( self . protocol ) {
481+ Ok ( p) => p. fmt ( f) ,
482+ Err ( _) => f
483+ . debug_struct ( "DevicePathNode" )
484+ . field ( "type" , & self . node_type ( ) )
485+ . field ( "sub_type" , & self . sub_type ( ) )
486+ . field ( "length" , & self . length ( ) )
487+ . field ( "specific_device_path_data" , & self . data ( ) )
488+ . finish ( ) ,
489+ }
298490 }
299491}
300492
0 commit comments