@@ -14,6 +14,8 @@ use r_efi::protocols::{device_path, device_path_to_text, shell};
14
14
15
15
use crate :: ffi:: { OsStr , OsString } ;
16
16
use crate :: io:: { self , const_error} ;
17
+ use crate :: iter:: Iterator ;
18
+ use crate :: marker:: PhantomData ;
17
19
use crate :: mem:: { MaybeUninit , size_of} ;
18
20
use crate :: os:: uefi:: env:: boot_services;
19
21
use crate :: os:: uefi:: ffi:: { OsStrExt , OsStringExt } ;
@@ -214,6 +216,60 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
214
216
Err ( io:: const_error!( io:: ErrorKind :: NotFound , "No device path to text protocol found" ) )
215
217
}
216
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
+
217
273
/// Gets RuntimeServices.
218
274
pub ( crate ) fn runtime_services ( ) -> Option < NonNull < r_efi:: efi:: RuntimeServices > > {
219
275
let system_table: NonNull < r_efi:: efi:: SystemTable > =
@@ -278,6 +334,10 @@ impl OwnedDevicePath {
278
334
pub ( crate ) const fn as_ptr ( & self ) -> * mut r_efi:: protocols:: device_path:: Protocol {
279
335
self . 0 . as_ptr ( )
280
336
}
337
+
338
+ pub ( crate ) const fn borrow < ' a > ( & ' a self ) -> BorrowedDevicePath < ' a > {
339
+ BorrowedDevicePath :: new ( self . 0 )
340
+ }
281
341
}
282
342
283
343
impl Drop for OwnedDevicePath {
@@ -293,8 +353,140 @@ impl Drop for OwnedDevicePath {
293
353
294
354
impl crate :: fmt:: Debug for OwnedDevicePath {
295
355
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 ) fn data ( & self ) -> & [ u8 ] {
434
+ let length: usize = self . length ( ) . into ( ) ;
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
+ }
298
490
}
299
491
}
300
492
0 commit comments