@@ -134,15 +134,40 @@ pub fn allocate_pages(ty: AllocateType, mem_ty: MemoryType, count: usize) -> Res
134134 let bt = boot_services_raw_panicking ( ) ;
135135 let bt = unsafe { bt. as_ref ( ) } ;
136136
137- let ( ty, mut addr ) = match ty {
137+ let ( ty, initial_addr ) = match ty {
138138 AllocateType :: AnyPages => ( 0 , 0 ) ,
139139 AllocateType :: MaxAddress ( addr) => ( 1 , addr) ,
140140 AllocateType :: Address ( addr) => ( 2 , addr) ,
141141 } ;
142- let addr =
143- unsafe { ( bt. allocate_pages ) ( ty, mem_ty, count, & mut addr) } . to_result_with_val ( || addr) ?;
144- let ptr = addr as * mut u8 ;
145- Ok ( NonNull :: new ( ptr) . expect ( "allocate_pages must not return a null pointer if successful" ) )
142+
143+ let mut addr1 = initial_addr;
144+ unsafe { ( bt. allocate_pages ) ( ty, mem_ty, count, & mut addr1) } . to_result ( ) ?;
145+
146+ // The UEFI spec allows `allocate_pages` to return a valid allocation at
147+ // address zero. Rust does not allow writes through a null pointer (which
148+ // Rust defines as address zero), so this is not very useful. Only return
149+ // the allocation if the address is non-null.
150+ if let Some ( ptr) = NonNull :: new ( addr1 as * mut u8 ) {
151+ return Ok ( ptr) ;
152+ }
153+
154+ // Attempt a second allocation. The first allocation (at address zero) has
155+ // not yet been freed, so if this allocation succeeds it should be at a
156+ // non-zero address.
157+ let mut addr2 = initial_addr;
158+ let r = unsafe { ( bt. allocate_pages ) ( ty, mem_ty, count, & mut addr2) } . to_result ( ) ;
159+
160+ // Free the original allocation (ignoring errors).
161+ let _unused = unsafe { ( bt. free_pages ) ( addr1, count) } ;
162+
163+ // Return an error if the second allocation failed, or if it is still at
164+ // address zero. Otherwise, return a pointer to the second allocation.
165+ r?;
166+ if let Some ( ptr) = NonNull :: new ( addr2 as * mut u8 ) {
167+ Ok ( ptr)
168+ } else {
169+ Err ( Status :: OUT_OF_RESOURCES . into ( ) )
170+ }
146171}
147172
148173/// Frees memory pages allocated by [`allocate_pages`].
@@ -467,6 +492,31 @@ pub fn check_event(event: Event) -> Result<bool> {
467492 }
468493}
469494
495+ /// Places the supplied `event` in the signaled state. If `event` is already in
496+ /// the signaled state, the function returns successfully. If `event` is of type
497+ /// [`NOTIFY_SIGNAL`], the event's notification function is scheduled to be
498+ /// invoked at the event's notification task priority level.
499+ ///
500+ /// This function may be invoked from any task priority level.
501+ ///
502+ /// If `event` is part of an event group, then all of the events in the event
503+ /// group are also signaled and their notification functions are scheduled.
504+ ///
505+ /// When signaling an event group, it is possible to create an event in the
506+ /// group, signal it and then close the event to remove it from the group.
507+ ///
508+ /// # Errors
509+ ///
510+ /// The specification does not list any errors.
511+ ///
512+ /// [`NOTIFY_SIGNAL`]: EventType::NOTIFY_SIGNAL
513+ pub fn signal_event ( event : & Event ) -> Result {
514+ let bt = boot_services_raw_panicking ( ) ;
515+ let bt = unsafe { bt. as_ref ( ) } ;
516+
517+ unsafe { ( bt. signal_event ) ( event. as_ptr ( ) ) } . to_result ( )
518+ }
519+
470520/// Removes `event` from any event group to which it belongs and closes it.
471521///
472522/// If `event` was registered with [`register_protocol_notify`], then the
0 commit comments