@@ -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`].
0 commit comments