@@ -216,6 +216,60 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
216
216
Err ( io:: const_error!( io:: ErrorKind :: NotFound , "no device path to text protocol found" ) )
217
217
}
218
218
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
+
219
273
/// Gets RuntimeServices.
220
274
pub ( crate ) fn runtime_services ( ) -> Option < NonNull < r_efi:: efi:: RuntimeServices > > {
221
275
let system_table: NonNull < r_efi:: efi:: SystemTable > =
@@ -319,6 +373,11 @@ impl<'a> BorrowedDevicePath<'a> {
319
373
pub ( crate ) fn to_text ( & self ) -> io:: Result < OsString > {
320
374
device_path_to_text ( self . protocol )
321
375
}
376
+
377
+ #[ expect( dead_code) ]
378
+ pub ( crate ) const fn iter ( & ' a self ) -> DevicePathIterator < ' a > {
379
+ DevicePathIterator :: new ( DevicePathNode :: new ( self . protocol ) )
380
+ }
322
381
}
323
382
324
383
impl < ' a > crate :: fmt:: Debug for BorrowedDevicePath < ' a > {
@@ -330,6 +389,126 @@ impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> {
330
389
}
331
390
}
332
391
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
+
333
512
pub ( crate ) struct OwnedProtocol < T > {
334
513
guid : r_efi:: efi:: Guid ,
335
514
handle : NonNull < crate :: ffi:: c_void > ,
0 commit comments