@@ -13,6 +13,7 @@ use core::cell::UnsafeCell;
13
13
use core:: ffi:: c_void;
14
14
use core:: fmt:: { Debug , Formatter } ;
15
15
use core:: mem:: { self , MaybeUninit } ;
16
+ use core:: ptr:: NonNull ;
16
17
use core:: { ptr, slice} ;
17
18
18
19
/// Contains pointers to all of the boot services.
@@ -48,17 +49,17 @@ pub struct BootServices {
48
49
ty : EventType ,
49
50
notify_tpl : Tpl ,
50
51
notify_func : Option < EventNotifyFn > ,
51
- notify_ctx : * mut c_void ,
52
- event : * mut Event ,
52
+ notify_ctx : Option < NonNull < c_void > > ,
53
+ out_event : * mut Event ,
53
54
) -> Status ,
54
55
set_timer : unsafe extern "efiapi" fn ( event : Event , ty : u32 , trigger_time : u64 ) -> Status ,
55
56
wait_for_event : unsafe extern "efiapi" fn (
56
57
number_of_events : usize ,
57
58
events : * mut Event ,
58
59
out_index : * mut usize ,
59
60
) -> Status ,
60
- signal_event : usize ,
61
- close_event : usize ,
61
+ signal_event : extern "efiapi" fn ( event : Event ) -> Status ,
62
+ close_event : unsafe extern "efiapi" fn ( event : Event ) -> Status ,
62
63
check_event : unsafe extern "efiapi" fn ( event : Event ) -> Status ,
63
64
64
65
// Protocol handlers
@@ -149,7 +150,14 @@ pub struct BootServices {
149
150
set_mem : unsafe extern "efiapi" fn ( buffer : * mut u8 , len : usize , value : u8 ) ,
150
151
151
152
// New event functions (UEFI 2.0 or newer)
152
- create_event_ex : usize ,
153
+ create_event_ex : unsafe extern "efiapi" fn (
154
+ ty : EventType ,
155
+ notify_tpl : Tpl ,
156
+ notify_fn : Option < EventNotifyFn > ,
157
+ notify_ctx : Option < NonNull < c_void > > ,
158
+ event_group : Option < NonNull < Guid > > ,
159
+ out_event : * mut Event ,
160
+ ) -> Status ,
153
161
}
154
162
155
163
impl BootServices {
@@ -307,44 +315,81 @@ impl BootServices {
307
315
& self ,
308
316
event_ty : EventType ,
309
317
notify_tpl : Tpl ,
310
- notify_fn : Option < fn ( Event ) > ,
318
+ notify_fn : Option < EventNotifyFn > ,
319
+ notify_ctx : Option < NonNull < c_void > > ,
311
320
) -> Result < Event > {
312
321
// Prepare storage for the output Event
313
322
let mut event = MaybeUninit :: < Event > :: uninit ( ) ;
314
323
315
- // Use a trampoline to handle the impedance mismatch between Rust & C
316
- unsafe extern "efiapi" fn notify_trampoline ( e : Event , ctx : * mut c_void ) {
317
- let notify_fn: fn ( Event ) = mem:: transmute ( ctx) ;
318
- notify_fn ( e) ; // SAFETY: Aborting panics are assumed here
319
- }
320
- let ( notify_func, notify_ctx) = notify_fn
321
- . map ( |notify_fn| {
322
- (
323
- Some ( notify_trampoline as EventNotifyFn ) ,
324
- notify_fn as fn ( Event ) as * mut c_void ,
325
- )
326
- } )
327
- . unwrap_or ( ( None , ptr:: null_mut ( ) ) ) ;
328
-
329
324
// Now we're ready to call UEFI
330
325
( self . create_event ) (
331
326
event_ty,
332
327
notify_tpl,
333
- notify_func,
328
+ notify_fn,
329
+ notify_ctx,
330
+ event. as_mut_ptr ( ) ,
331
+ )
332
+ . into_with_val ( || event. assume_init ( ) )
333
+ }
334
+
335
+ /// Creates a new `Event` of type `event_type`. The event's notification function, context,
336
+ /// and task priority are specified by `notify_fn`, `notify_ctx`, and `notify_tpl`, respectively.
337
+ /// The `Event` will be added to the group of `Event`s identified by `event_group`.
338
+ ///
339
+ /// If no group is specified by `event_group`, this function behaves as if the same parameters
340
+ /// had been passed to `create_event()`.
341
+ ///
342
+ /// Event groups are collections of events identified by a shared `Guid` where, when one member
343
+ /// event is signaled, all other events are signaled and their individual notification actions
344
+ /// are taken. All events are guaranteed to be signaled before the first notification action is
345
+ /// taken. All notification functions will be executed in the order specified by their `Tpl`.
346
+ ///
347
+ /// A single event can only be part of a single event group. An event may be removed from an
348
+ /// event group by using `close_event()`.
349
+ ///
350
+ /// The `EventType` of an event uses the same values as `create_event()`, except that
351
+ /// `EventType::SIGNAL_EXIT_BOOT_SERVICES` and `EventType::SIGNAL_VIRTUAL_ADDRESS_CHANGE`
352
+ /// are not valid.
353
+ ///
354
+ /// If `event_type` has `EventType::NOTIFY_SIGNAL` or `EventType::NOTIFY_WAIT`, then `notify_fn`
355
+ /// mus be `Some` and `notify_tpl` must be a valid task priority level, otherwise these parameters
356
+ /// are ignored.
357
+ ///
358
+ /// More than one event of type `EventType::TIMER` may be part of a single event group. However,
359
+ /// there is no mechanism for determining which of the timers was signaled.
360
+ ///
361
+ /// # Safety
362
+ ///
363
+ /// The caller must ensure they are passing a valid `Guid` as `event_group`, if applicable.
364
+ pub unsafe fn create_event_ex (
365
+ & self ,
366
+ event_type : EventType ,
367
+ notify_tpl : Tpl ,
368
+ notify_fn : Option < EventNotifyFn > ,
369
+ notify_ctx : Option < NonNull < c_void > > ,
370
+ event_group : Option < NonNull < Guid > > ,
371
+ ) -> Result < Event > {
372
+ let mut event = MaybeUninit :: < Event > :: uninit ( ) ;
373
+
374
+ ( self . create_event_ex ) (
375
+ event_type,
376
+ notify_tpl,
377
+ notify_fn,
334
378
notify_ctx,
379
+ event_group,
335
380
event. as_mut_ptr ( ) ,
336
381
)
337
382
. into_with_val ( || event. assume_init ( ) )
338
383
}
339
384
340
385
/// Sets the trigger for `EventType::TIMER` event.
341
- pub fn set_timer ( & self , event : Event , trigger_time : TimerTrigger ) -> Result {
386
+ pub fn set_timer ( & self , event : & Event , trigger_time : TimerTrigger ) -> Result {
342
387
let ( ty, time) = match trigger_time {
343
388
TimerTrigger :: Cancel => ( 0 , 0 ) ,
344
389
TimerTrigger :: Periodic ( hundreds_ns) => ( 1 , hundreds_ns) ,
345
390
TimerTrigger :: Relative ( hundreds_ns) => ( 2 , hundreds_ns) ,
346
391
} ;
347
- unsafe { ( self . set_timer ) ( event, ty, time) } . into ( )
392
+ unsafe { ( self . set_timer ) ( event. unsafe_clone ( ) , ty, time) } . into ( )
348
393
}
349
394
350
395
/// Stops execution until an event is signaled.
@@ -389,6 +434,35 @@ impl BootServices {
389
434
)
390
435
}
391
436
437
+ /// Place 'event' in the signaled stated. If 'event' is already in the signaled state,
438
+ /// then nothing further occurs and `Status::SUCCESS` is returned. If `event` is of type
439
+ /// `EventType::NOTIFY_SIGNAL`, then the event's notification function is scheduled to
440
+ /// be invoked at the event's notification task priority level.
441
+ ///
442
+ /// This function may be invoked from any task priority level.
443
+ ///
444
+ /// If `event` is part of an event group, then all of the events in the event group are
445
+ /// also signaled and their notification functions are scheduled.
446
+ ///
447
+ /// When signaling an event group, it is possible to create an event in the group, signal
448
+ /// it, and then close the event to remove it from the group.
449
+ pub fn signal_event ( & self , event : & Event ) -> Result {
450
+ // Safety: cloning this event should be safe, as we're directly passing it to firmware
451
+ // and not keeping the clone around.
452
+ unsafe { ( self . signal_event ) ( event. unsafe_clone ( ) ) . into ( ) }
453
+ }
454
+
455
+ /// Removes `event` from any event group to which it belongs and closes it. If `event` was
456
+ /// registered with `register_protocol_notify()`, then the corresponding registration will
457
+ /// be removed. It is safe to call this function within the corresponding notify function.
458
+ ///
459
+ ///
460
+ /// Note: The UEFI Specification v2.9 states that this may only return `EFI_SUCCESS`, but,
461
+ /// at least for application based on EDK2 (such as OVMF), it may also return `EFI_INVALID_PARAMETER`.
462
+ pub fn close_event ( & self , event : Event ) -> Result {
463
+ unsafe { ( self . close_event ) ( event) . into ( ) }
464
+ }
465
+
392
466
/// Checks to see if an event is signaled, without blocking execution to wait for it.
393
467
///
394
468
/// The returned value will be `true` if the event is in the signaled state,
@@ -1116,7 +1190,7 @@ bitflags! {
1116
1190
}
1117
1191
1118
1192
/// Raw event notification function
1119
- type EventNotifyFn = unsafe extern "efiapi" fn ( event : Event , context : * mut c_void ) ;
1193
+ type EventNotifyFn = unsafe extern "efiapi" fn ( event : Event , context : Option < NonNull < c_void > > ) ;
1120
1194
1121
1195
/// Timer events manipulation
1122
1196
pub enum TimerTrigger {
0 commit comments