summaryrefslogtreecommitdiffstats
path: root/library/std/src/os/uefi/env.rs
blob: 5d082e7c113882c4490a1cf39201038c662eefb0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! UEFI-specific extensions to the primitives in `std::env` module

#![unstable(feature = "uefi_std", issue = "100499")]

use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use crate::{ffi::c_void, ptr::NonNull};

static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
// Flag to check if BootServices are still valid.
// Start with assuming that they are not available
static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);

/// Initializes the global System Table and Image Handle pointers.
///
/// The standard library requires access to the UEFI System Table and the Application Image Handle
/// to operate. Those are provided to UEFI Applications via their application entry point. By
/// calling `init_globals()`, those pointers are retained by the standard library for future use.
/// Thus this function must be called before any of the standard library services are used.
///
/// The pointers are never exposed to any entity outside of this application and it is guaranteed
/// that, once the application exited, these pointers are never dereferenced again.
///
/// Callers are required to ensure the pointers are valid for the entire lifetime of this
/// application. In particular, UEFI Boot Services must not be exited while an application with the
/// standard library is loaded.
///
/// # SAFETY
/// Calling this function more than once will panic
pub(crate) unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
    IMAGE_HANDLE
        .compare_exchange(
            crate::ptr::null_mut(),
            handle.as_ptr(),
            Ordering::Release,
            Ordering::Acquire,
        )
        .unwrap();
    SYSTEM_TABLE
        .compare_exchange(
            crate::ptr::null_mut(),
            system_table.as_ptr(),
            Ordering::Release,
            Ordering::Acquire,
        )
        .unwrap();
    BOOT_SERVICES_FLAG.store(true, Ordering::Release)
}

/// Get the SystemTable Pointer.
/// If you want to use `BootServices` then please use [`boot_services`] as it performs some
/// additional checks.
///
/// Note: This function panics if the System Table or Image Handle is not initialized
pub fn system_table() -> NonNull<c_void> {
    try_system_table().unwrap()
}

/// Get the ImageHandle Pointer.
///
/// Note: This function panics if the System Table or Image Handle is not initialized
pub fn image_handle() -> NonNull<c_void> {
    try_image_handle().unwrap()
}

/// Get the BootServices Pointer.
/// This function also checks if `ExitBootServices` has already been called.
pub fn boot_services() -> Option<NonNull<c_void>> {
    if BOOT_SERVICES_FLAG.load(Ordering::Acquire) {
        let system_table: NonNull<r_efi::efi::SystemTable> = try_system_table()?.cast();
        let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
        NonNull::new(boot_services).map(|x| x.cast())
    } else {
        None
    }
}

/// Get the SystemTable Pointer.
/// This function is mostly intended for places where panic is not an option
pub(crate) fn try_system_table() -> Option<NonNull<c_void>> {
    NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire))
}

/// Get the SystemHandle Pointer.
/// This function is mostly intended for places where panicking is not an option
pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> {
    NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
}

pub(crate) fn disable_boot_services() {
    BOOT_SERVICES_FLAG.store(false, Ordering::Release)
}