@@ -18,6 +18,20 @@ use core::ops::{Deref, DerefMut};
1818use core:: ptr:: NonNull ;
1919use core:: { ptr, slice} ;
2020
21+ // TODO: this similar to `SyncUnsafeCell`. Once that is stabilized we
22+ // can use it instead.
23+ struct GlobalImageHandle {
24+ handle : UnsafeCell < Option < Handle > > ,
25+ }
26+
27+ // Safety: reads and writes are managed via `set_image_handle` and
28+ // `BootServices::image_handle`.
29+ unsafe impl Sync for GlobalImageHandle { }
30+
31+ static IMAGE_HANDLE : GlobalImageHandle = GlobalImageHandle {
32+ handle : UnsafeCell :: new ( None ) ,
33+ } ;
34+
2135/// Contains pointers to all of the boot services.
2236///
2337/// # Accessing `BootServices`
@@ -238,6 +252,46 @@ pub struct BootServices {
238252}
239253
240254impl BootServices {
255+ /// Get the [`Handle`] of the currently-executing image.
256+ pub fn image_handle ( & self ) -> Handle {
257+ // Safety:
258+ //
259+ // `IMAGE_HANDLE` is only set by `set_image_handle`, see that
260+ // documentation for more details.
261+ //
262+ // Additionally, `image_handle` takes a `&self` which ensures it
263+ // can only be called while boot services are active. (After
264+ // exiting boot services, the image handle should not be
265+ // considered valid.)
266+ unsafe {
267+ IMAGE_HANDLE
268+ . handle
269+ . get ( )
270+ . read ( )
271+ . expect ( "set_image_handle has not been called" )
272+ }
273+ }
274+
275+ /// Update the global image [`Handle`].
276+ ///
277+ /// This is called automatically in the `main` entry point as part
278+ /// of [`uefi_macros::entry`]. It should not be called at any other
279+ /// point in time, unless the executable does not use
280+ /// [`uefi_macros::entry`], in which case it should be called once
281+ /// before calling other `BootServices` functions.
282+ ///
283+ /// # Safety
284+ ///
285+ /// This function should only be called as described above. The
286+ /// safety guarantees of [`BootServices::open_protocol_exclusive`]
287+ /// rely on the global image handle being correct.
288+ pub unsafe fn set_image_handle ( & self , image_handle : Handle ) {
289+ // As with `image_handle`, `&self` isn't actually used, but it
290+ // enforces that this function is only called while boot
291+ // services are active.
292+ IMAGE_HANDLE . handle . get ( ) . write ( Some ( image_handle) ) ;
293+ }
294+
241295 /// Raises a task's priority level and returns its previous level.
242296 ///
243297 /// The effect of calling `raise_tpl` with a `Tpl` that is below the current
0 commit comments