@@ -13,6 +13,7 @@ use core::cell::UnsafeCell;
1313use  core:: ffi:: c_void; 
1414use  core:: fmt:: { Debug ,  Formatter } ; 
1515use  core:: mem:: { self ,  MaybeUninit } ; 
16+ use  core:: ptr:: NonNull ; 
1617use  core:: { ptr,  slice} ; 
1718
1819/// Contains pointers to all of the boot services. 
@@ -48,17 +49,17 @@ pub struct BootServices {
4849 ty :  EventType , 
4950 notify_tpl :  Tpl , 
5051 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 , 
5354 )  -> Status , 
5455 set_timer :  unsafe  extern  "efiapi"  fn ( event :  Event ,  ty :  u32 ,  trigger_time :  u64 )  -> Status , 
5556 wait_for_event :  unsafe  extern  "efiapi"  fn ( 
5657 number_of_events :  usize , 
5758 events :  * mut  Event , 
5859 out_index :  * mut  usize , 
5960 )  -> 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 , 
6263 check_event :  unsafe  extern  "efiapi"  fn ( event :  Event )  -> Status , 
6364
6465 // Protocol handlers 
@@ -149,7 +150,14 @@ pub struct BootServices {
149150 set_mem :  unsafe  extern  "efiapi"  fn ( buffer :  * mut  u8 ,  len :  usize ,  value :  u8 ) , 
150151
151152 // 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 , 
153161} 
154162
155163impl  BootServices  { 
@@ -307,44 +315,81 @@ impl BootServices {
307315 & self , 
308316 event_ty :  EventType , 
309317 notify_tpl :  Tpl , 
310-  notify_fn :  Option < fn ( Event ) > , 
318+  notify_fn :  Option < EventNotifyFn > , 
319+  notify_ctx :  Option < NonNull < c_void > > , 
311320 )  -> Result < Event >  { 
312321 // Prepare storage for the output Event 
313322 let  mut  event = MaybeUninit :: < Event > :: uninit ( ) ; 
314323
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- 
329324 // Now we're ready to call UEFI 
330325 ( self . create_event ) ( 
331326 event_ty, 
332327 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, 
334378 notify_ctx, 
379+  event_group, 
335380 event. as_mut_ptr ( ) , 
336381 ) 
337382 . into_with_val ( || event. assume_init ( ) ) 
338383 } 
339384
340385 /// 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  { 
342387 let  ( ty,  time)  = match  trigger_time { 
343388 TimerTrigger :: Cancel  => ( 0 ,  0 ) , 
344389 TimerTrigger :: Periodic ( hundreds_ns)  => ( 1 ,  hundreds_ns) , 
345390 TimerTrigger :: Relative ( hundreds_ns)  => ( 2 ,  hundreds_ns) , 
346391 } ; 
347-  unsafe  {  ( self . set_timer ) ( event,  ty,  time)  } . into ( ) 
392+  unsafe  {  ( self . set_timer ) ( event. unsafe_clone ( ) ,  ty,  time)  } . into ( ) 
348393 } 
349394
350395 /// Stops execution until an event is signaled. 
@@ -389,6 +434,35 @@ impl BootServices {
389434 ) 
390435 } 
391436
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+ 
392466 /// Checks to see if an event is signaled, without blocking execution to wait for it. 
393467/// 
394468/// The returned value will be `true` if the event is in the signaled state, 
@@ -1116,7 +1190,7 @@ bitflags! {
11161190} 
11171191
11181192/// 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 > > ) ; 
11201194
11211195/// Timer events manipulation 
11221196pub  enum  TimerTrigger  { 
0 commit comments