@@ -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_io_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 } ;
@@ -22,6 +24,7 @@ use crate::ptr::NonNull;
22
24
use crate :: slice;
23
25
use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
24
26
use crate :: sys_common:: wstr:: WStrUnits ;
27
+ use crate :: time:: Duration ;
25
28
26
29
type BootInstallMultipleProtocolInterfaces =
27
30
unsafe extern "efiapi" fn ( _: * mut r_efi:: efi:: Handle , _: ...) -> r_efi:: efi:: Status ;
@@ -162,11 +165,11 @@ pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> io::Result<NonNul
162
165
open_protocol ( system_handle, protocol_guid)
163
166
}
164
167
165
- pub ( crate ) fn device_path_to_text ( path : NonNull < device_path:: Protocol > ) -> io:: Result < OsString > {
168
+ fn device_path_to_text_raw ( path : NonNull < device_path:: Protocol > ) -> io:: Result < Box < [ u16 ] > > {
166
169
fn path_to_text (
167
170
protocol : NonNull < device_path_to_text:: Protocol > ,
168
171
path : NonNull < device_path:: Protocol > ,
169
- ) -> io:: Result < OsString > {
172
+ ) -> io:: Result < Box < [ u16 ] > > {
170
173
let path_ptr: * mut r_efi:: efi:: Char16 = unsafe {
171
174
( ( * protocol. as_ptr ( ) ) . convert_device_path_to_text ) (
172
175
path. as_ptr ( ) ,
@@ -177,6 +180,56 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
177
180
)
178
181
} ;
179
182
183
+ owned_uefi_string_from_raw ( path_ptr)
184
+ . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidData , "Invalid path" ) )
185
+ }
186
+
187
+ static LAST_VALID_HANDLE : AtomicPtr < crate :: ffi:: c_void > =
188
+ AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ;
189
+
190
+ if let Some ( handle) = NonNull :: new ( LAST_VALID_HANDLE . load ( Ordering :: Acquire ) ) {
191
+ if let Ok ( protocol) = open_protocol :: < device_path_to_text:: Protocol > (
192
+ handle,
193
+ device_path_to_text:: PROTOCOL_GUID ,
194
+ ) {
195
+ return path_to_text ( protocol, path) ;
196
+ }
197
+ }
198
+
199
+ let device_path_to_text_handles = locate_handles ( device_path_to_text:: PROTOCOL_GUID ) ?;
200
+ for handle in device_path_to_text_handles {
201
+ if let Ok ( protocol) = open_protocol :: < device_path_to_text:: Protocol > (
202
+ handle,
203
+ device_path_to_text:: PROTOCOL_GUID ,
204
+ ) {
205
+ LAST_VALID_HANDLE . store ( handle. as_ptr ( ) , Ordering :: Release ) ;
206
+ return path_to_text ( protocol, path) ;
207
+ }
208
+ }
209
+
210
+ Err ( io:: const_io_error!( io:: ErrorKind :: NotFound , "No device path to text protocol found" ) )
211
+ }
212
+
213
+ pub ( crate ) fn device_path_to_text ( path : NonNull < device_path:: Protocol > ) -> io:: Result < OsString > {
214
+ let p = device_path_to_text_raw ( path) ?;
215
+ Ok ( OsString :: from_wide ( & p) )
216
+ }
217
+
218
+ fn device_node_to_text ( path : NonNull < device_path:: Protocol > ) -> io:: Result < OsString > {
219
+ fn node_to_text (
220
+ protocol : NonNull < device_path_to_text:: Protocol > ,
221
+ path : NonNull < device_path:: Protocol > ,
222
+ ) -> io:: Result < OsString > {
223
+ let path_ptr: * mut r_efi:: efi:: Char16 = unsafe {
224
+ ( ( * protocol. as_ptr ( ) ) . convert_device_node_to_text ) (
225
+ path. as_ptr ( ) ,
226
+ // DisplayOnly
227
+ r_efi:: efi:: Boolean :: FALSE ,
228
+ // AllowShortcuts
229
+ r_efi:: efi:: Boolean :: FALSE ,
230
+ )
231
+ } ;
232
+
180
233
let path = os_string_from_raw ( path_ptr)
181
234
. ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidData , "Invalid path" ) ) ?;
182
235
@@ -198,7 +251,7 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
198
251
handle,
199
252
device_path_to_text:: PROTOCOL_GUID ,
200
253
) {
201
- return path_to_text ( protocol, path) ;
254
+ return node_to_text ( protocol, path) ;
202
255
}
203
256
}
204
257
@@ -209,7 +262,7 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
209
262
device_path_to_text:: PROTOCOL_GUID ,
210
263
) {
211
264
LAST_VALID_HANDLE . store ( handle. as_ptr ( ) , Ordering :: Release ) ;
212
- return path_to_text ( protocol, path) ;
265
+ return node_to_text ( protocol, path) ;
213
266
}
214
267
}
215
268
@@ -224,14 +277,14 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
224
277
NonNull :: new ( runtime_services)
225
278
}
226
279
227
- pub ( crate ) struct DevicePath ( NonNull < r_efi:: protocols:: device_path:: Protocol > ) ;
280
+ pub ( crate ) struct OwnedDevicePath ( pub ( crate ) NonNull < r_efi:: protocols:: device_path:: Protocol > ) ;
228
281
229
- impl DevicePath {
282
+ impl OwnedDevicePath {
230
283
pub ( crate ) fn from_text ( p : & OsStr ) -> io:: Result < Self > {
231
284
fn inner (
232
285
p : & OsStr ,
233
286
protocol : NonNull < r_efi:: protocols:: device_path_from_text:: Protocol > ,
234
- ) -> io:: Result < DevicePath > {
287
+ ) -> io:: Result < OwnedDevicePath > {
235
288
let path_vec = p. encode_wide ( ) . chain ( Some ( 0 ) ) . collect :: < Vec < u16 > > ( ) ;
236
289
if path_vec[ ..path_vec. len ( ) - 1 ] . contains ( & 0 ) {
237
290
return Err ( const_io_error ! (
@@ -243,7 +296,7 @@ impl DevicePath {
243
296
let path =
244
297
unsafe { ( ( * protocol. as_ptr ( ) ) . convert_text_to_device_path ) ( path_vec. as_ptr ( ) ) } ;
245
298
246
- NonNull :: new ( path) . map ( DevicePath ) . ok_or_else ( || {
299
+ NonNull :: new ( path) . map ( OwnedDevicePath ) . ok_or_else ( || {
247
300
const_io_error ! ( io:: ErrorKind :: InvalidFilename , "Invalid Device Path" )
248
301
} )
249
302
}
@@ -277,12 +330,16 @@ impl DevicePath {
277
330
) )
278
331
}
279
332
280
- pub ( crate ) fn as_ptr ( & self ) -> * mut r_efi:: protocols:: device_path:: Protocol {
333
+ pub ( crate ) const fn as_ptr ( & self ) -> * mut r_efi:: protocols:: device_path:: Protocol {
281
334
self . 0 . as_ptr ( )
282
335
}
336
+
337
+ pub ( crate ) const fn borrow < ' a > ( & ' a self ) -> BorrowedDevicePath < ' a > {
338
+ BorrowedDevicePath :: new ( self . 0 )
339
+ }
283
340
}
284
341
285
- impl Drop for DevicePath {
342
+ impl Drop for OwnedDevicePath {
286
343
fn drop ( & mut self ) {
287
344
if let Some ( bt) = boot_services ( ) {
288
345
let bt: NonNull < r_efi:: efi:: BootServices > = bt. cast ( ) ;
@@ -293,6 +350,136 @@ impl Drop for DevicePath {
293
350
}
294
351
}
295
352
353
+ impl crate :: fmt:: Debug for OwnedDevicePath {
354
+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
355
+ let p = device_path_to_text ( self . 0 ) . unwrap ( ) ;
356
+ p. 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_raw ( & self ) -> io:: Result < Box < [ u16 ] > > {
375
+ device_path_to_text_raw ( self . protocol )
376
+ }
377
+
378
+ pub ( crate ) fn to_text ( & self ) -> io:: Result < OsString > {
379
+ device_path_to_text ( self . protocol )
380
+ }
381
+ }
382
+
383
+ impl < ' a > crate :: fmt:: Debug for BorrowedDevicePath < ' a > {
384
+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
385
+ let p = self . to_text ( ) . unwrap ( ) ;
386
+ p. fmt ( f)
387
+ }
388
+ }
389
+
390
+ pub ( crate ) struct DevicePathIterator < ' a > ( Option < DevicePathNode < ' a > > ) ;
391
+
392
+ impl < ' a > DevicePathIterator < ' a > {
393
+ const fn new ( node : DevicePathNode < ' a > ) -> Self {
394
+ if node. is_end ( ) { Self ( None ) } else { Self ( Some ( node) ) }
395
+ }
396
+ }
397
+
398
+ impl < ' a > Iterator for DevicePathIterator < ' a > {
399
+ type Item = DevicePathNode < ' a > ;
400
+
401
+ fn next ( & mut self ) -> Option < Self :: Item > {
402
+ let cur_node = self . 0 ?;
403
+
404
+ let next_node = unsafe { cur_node. next_node ( ) } ;
405
+ self . 0 = if next_node. is_end ( ) { None } else { Some ( next_node) } ;
406
+
407
+ Some ( cur_node)
408
+ }
409
+ }
410
+
411
+ #[ derive( Copy , Clone ) ]
412
+ pub ( crate ) struct DevicePathNode < ' a > {
413
+ protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ,
414
+ phantom : PhantomData < & ' a r_efi:: protocols:: device_path:: Protocol > ,
415
+ }
416
+
417
+ impl < ' a > DevicePathNode < ' a > {
418
+ pub ( crate ) const fn new ( protocol : NonNull < r_efi:: protocols:: device_path:: Protocol > ) -> Self {
419
+ Self { protocol, phantom : PhantomData }
420
+ }
421
+
422
+ pub ( crate ) const fn length ( & self ) -> u16 {
423
+ let len = unsafe { ( * self . protocol . as_ptr ( ) ) . length } ;
424
+ u16:: from_le_bytes ( len)
425
+ }
426
+
427
+ pub ( crate ) const fn node_type ( & self ) -> u8 {
428
+ unsafe { ( * self . protocol . as_ptr ( ) ) . r#type }
429
+ }
430
+
431
+ pub ( crate ) const fn sub_type ( & self ) -> u8 {
432
+ unsafe { ( * self . protocol . as_ptr ( ) ) . sub_type }
433
+ }
434
+
435
+ pub ( crate ) const fn is_end ( & self ) -> bool {
436
+ self . node_type ( ) == r_efi:: protocols:: device_path:: TYPE_END
437
+ && self . sub_type ( ) == r_efi:: protocols:: device_path:: End :: SUBTYPE_ENTIRE
438
+ }
439
+
440
+ pub ( crate ) const fn is_end_instance ( & self ) -> bool {
441
+ self . node_type ( ) == r_efi:: protocols:: device_path:: TYPE_END
442
+ && self . sub_type ( ) == r_efi:: protocols:: device_path:: End :: SUBTYPE_INSTANCE
443
+ }
444
+
445
+ pub ( crate ) unsafe fn next_node ( & self ) -> Self {
446
+ let node = unsafe {
447
+ self . protocol
448
+ . cast :: < u8 > ( )
449
+ . add ( self . length ( ) . into ( ) )
450
+ . cast :: < r_efi:: protocols:: device_path:: Protocol > ( )
451
+ } ;
452
+ Self :: new ( node)
453
+ }
454
+
455
+ pub ( crate ) fn to_path ( & ' a self ) -> BorrowedDevicePath < ' a > {
456
+ BorrowedDevicePath :: new ( self . protocol )
457
+ }
458
+ }
459
+
460
+ impl < ' a > PartialEq for DevicePathNode < ' a > {
461
+ fn eq ( & self , other : & Self ) -> bool {
462
+ let self_len = self . length ( ) ;
463
+ let other_len = other. length ( ) ;
464
+
465
+ self_len == other_len
466
+ && unsafe {
467
+ compiler_builtins:: mem:: memcmp (
468
+ self . protocol . as_ptr ( ) . cast ( ) ,
469
+ other. protocol . as_ptr ( ) . cast ( ) ,
470
+ usize:: from ( self_len) ,
471
+ ) == 0
472
+ }
473
+ }
474
+ }
475
+
476
+ impl < ' a > crate :: fmt:: Debug for DevicePathNode < ' a > {
477
+ fn fmt ( & self , f : & mut crate :: fmt:: Formatter < ' _ > ) -> crate :: fmt:: Result {
478
+ let p = device_node_to_text ( self . protocol ) . unwrap ( ) ;
479
+ p. fmt ( f)
480
+ }
481
+ }
482
+
296
483
pub ( crate ) struct OwnedProtocol < T > {
297
484
guid : r_efi:: efi:: Guid ,
298
485
handle : NonNull < crate :: ffi:: c_void > ,
@@ -413,6 +600,15 @@ impl<T> Drop for OwnedTable<T> {
413
600
}
414
601
}
415
602
603
+ /// Create an Owned UEFI string from raw pointer. Allows string allocations and conversions
604
+ ///
605
+ /// SAFETY: This function assumes that Rust has ownership over this string
606
+ fn owned_uefi_string_from_raw ( ptr : * mut r_efi:: efi:: Char16 ) -> Option < Box < [ r_efi:: efi:: Char16 ] > > {
607
+ let str_len = unsafe { WStrUnits :: new ( ptr) ?. count ( ) } ;
608
+ let str_slice = crate :: ptr:: slice_from_raw_parts_mut ( ptr. cast ( ) , str_len) ;
609
+ Some ( unsafe { Box :: from_raw ( str_slice) } )
610
+ }
611
+
416
612
/// Create OsString from a pointer to NULL terminated UTF-16 string
417
613
pub ( crate ) fn os_string_from_raw ( ptr : * mut r_efi:: efi:: Char16 ) -> Option < OsString > {
418
614
let path_len = unsafe { WStrUnits :: new ( ptr) ?. count ( ) } ;
@@ -445,3 +641,47 @@ pub(crate) fn open_shell() -> Option<NonNull<shell::Protocol>> {
445
641
446
642
None
447
643
}
644
+
645
+ // This algorithm is taken from: http://howardhinnant.github.io/date_algorithms.html
646
+ pub const fn uefi_time_from_duration (
647
+ dur : Duration ,
648
+ daylight : u8 ,
649
+ timezone : i16 ,
650
+ ) -> r_efi:: system:: Time {
651
+ const SECS_IN_MINUTE : u64 = 60 ;
652
+ const SECS_IN_HOUR : u64 = SECS_IN_MINUTE * 60 ;
653
+ const SECS_IN_DAY : u64 = SECS_IN_HOUR * 24 ;
654
+
655
+ let secs = dur. as_secs ( ) ;
656
+
657
+ let days = secs / SECS_IN_DAY ;
658
+ let remaining_secs = secs % SECS_IN_DAY ;
659
+
660
+ let z = days + 719468 ;
661
+ let era = z / 146097 ;
662
+ let doe = z - ( era * 146097 ) ;
663
+ let yoe = ( doe - doe / 1460 + doe / 36524 - doe / 146096 ) / 365 ;
664
+ let mut y = yoe + era * 400 ;
665
+ let doy = doe - ( 365 * yoe + yoe / 4 - yoe / 100 ) ;
666
+ let mp = ( 5 * doy + 2 ) / 153 ;
667
+ let d = doy - ( 153 * mp + 2 ) / 5 + 1 ;
668
+ let m = if mp < 10 { mp + 3 } else { mp - 9 } ;
669
+
670
+ if m <= 2 {
671
+ y += 1 ;
672
+ }
673
+
674
+ r_efi:: system:: Time {
675
+ year : y as u16 ,
676
+ month : m as u8 ,
677
+ day : d as u8 ,
678
+ hour : ( remaining_secs / SECS_IN_HOUR ) as u8 ,
679
+ minute : ( ( remaining_secs % SECS_IN_HOUR ) / SECS_IN_MINUTE ) as u8 ,
680
+ second : ( ( remaining_secs % SECS_IN_HOUR ) % SECS_IN_MINUTE ) as u8 ,
681
+ pad1 : 0 ,
682
+ nanosecond : dur. subsec_nanos ( ) ,
683
+ timezone,
684
+ daylight,
685
+ pad2 : 0 ,
686
+ }
687
+ }
0 commit comments