Skip to content

Commit 763cfef

Browse files
committed
Auto merge of rust-lang#105861 - Ayush1325:uefi-std-minimial, r=workingjubilee
Add Minimal Std implementation for UEFI # Implemented modules: 1. alloc 2. os_str 3. env 4. math # Related Links Tracking Issue: rust-lang#100499 API Change Proposal: rust-lang/libs-team#87 # Additional Information This was originally part of rust-lang#100316. Since that PR was becoming too unwieldy and cluttered, and with suggestion from `@dvdhrm,` I have extracted a minimal std implementation to this PR. The example in `src/doc/rustc/src/platform-support/unknown-uefi.md` has been tested for `x86_64-unknown-uefi` and `i686-unknown-uefi` in OVMF. It would be great if someone more familiar with AARCH64 can help with testing for that target. Signed-off-by: Ayush Singh <ayushsingh1325@gmail.com>
2 parents be8f319 + 1ca9b41 commit 763cfef

File tree

17 files changed

+829
-7
lines changed

17 files changed

+829
-7
lines changed

panic_abort/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
4444
}
4545
} else if #[cfg(any(target_os = "hermit",
4646
all(target_vendor = "fortanix", target_env = "sgx"),
47-
target_os = "xous"
47+
target_os = "xous",
48+
target_os = "uefi",
4849
))] {
4950
unsafe fn abort() -> ! {
5051
// call std::sys::abort_internal

std/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ hermit-abi = { version = "0.3.2", features = ['rustc-dep-of-std'], public = true
4848
[target.'cfg(target_os = "wasi")'.dependencies]
4949
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
5050

51+
[target.'cfg(target_os = "uefi")'.dependencies]
52+
r-efi = { version = "4.2.0", features = ['rustc-dep-of-std']}
53+
r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std']}
54+
5155
[features]
5256
backtrace = [
5357
"gimli-symbolize",

std/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn main() {
3939
|| target.contains("nto")
4040
|| target.contains("xous")
4141
|| target.contains("hurd")
42+
|| target.contains("uefi")
4243
// See src/bootstrap/synthetic_targets.rs
4344
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
4445
{
@@ -51,7 +52,6 @@ fn main() {
5152
// - mipsel-sony-psp
5253
// - nvptx64-nvidia-cuda
5354
// - arch=avr
54-
// - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
5555
// - JSON targets
5656
// - Any new targets that have not been explicitly added above.
5757
println!("cargo:rustc-cfg=feature=\"restricted-std\"");

std/src/io/error.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#[cfg(test)]
22
mod tests;
33

4-
#[cfg(target_pointer_width = "64")]
4+
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
55
mod repr_bitpacked;
6-
#[cfg(target_pointer_width = "64")]
6+
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
77
use repr_bitpacked::Repr;
88

9-
#[cfg(not(target_pointer_width = "64"))]
9+
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
1010
mod repr_unpacked;
11-
#[cfg(not(target_pointer_width = "64"))]
11+
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
1212
use repr_unpacked::Repr;
1313

1414
use crate::error;

std/src/os/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ pub mod solid;
142142
#[cfg(target_os = "tvos")]
143143
#[path = "ios/mod.rs"]
144144
pub(crate) mod tvos;
145+
#[cfg(target_os = "uefi")]
146+
pub mod uefi;
145147
#[cfg(target_os = "vita")]
146148
pub mod vita;
147149
#[cfg(target_os = "vxworks")]

std/src/os/uefi/env.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! UEFI-specific extensions to the primitives in `std::env` module
2+
3+
#![unstable(feature = "uefi_std", issue = "100499")]
4+
5+
use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
6+
use crate::{ffi::c_void, ptr::NonNull};
7+
8+
static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
9+
static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
10+
// Flag to check if BootServices are still valid.
11+
// Start with assuming that they are not available
12+
static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
13+
14+
/// Initializes the global System Table and Image Handle pointers.
15+
///
16+
/// The standard library requires access to the UEFI System Table and the Application Image Handle
17+
/// to operate. Those are provided to UEFI Applications via their application entry point. By
18+
/// calling `init_globals()`, those pointers are retained by the standard library for future use.
19+
/// Thus this function must be called before any of the standard library services are used.
20+
///
21+
/// The pointers are never exposed to any entity outside of this application and it is guaranteed
22+
/// that, once the application exited, these pointers are never dereferenced again.
23+
///
24+
/// Callers are required to ensure the pointers are valid for the entire lifetime of this
25+
/// application. In particular, UEFI Boot Services must not be exited while an application with the
26+
/// standard library is loaded.
27+
///
28+
/// # SAFETY
29+
/// Calling this function more than once will panic
30+
pub(crate) unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
31+
IMAGE_HANDLE
32+
.compare_exchange(
33+
crate::ptr::null_mut(),
34+
handle.as_ptr(),
35+
Ordering::Release,
36+
Ordering::Acquire,
37+
)
38+
.unwrap();
39+
SYSTEM_TABLE
40+
.compare_exchange(
41+
crate::ptr::null_mut(),
42+
system_table.as_ptr(),
43+
Ordering::Release,
44+
Ordering::Acquire,
45+
)
46+
.unwrap();
47+
BOOT_SERVICES_FLAG.store(true, Ordering::Release)
48+
}
49+
50+
/// Get the SystemTable Pointer.
51+
/// If you want to use `BootServices` then please use [`boot_services`] as it performs some
52+
/// additional checks.
53+
///
54+
/// Note: This function panics if the System Table or Image Handle is not initialized
55+
pub fn system_table() -> NonNull<c_void> {
56+
try_system_table().unwrap()
57+
}
58+
59+
/// Get the ImageHandle Pointer.
60+
///
61+
/// Note: This function panics if the System Table or Image Handle is not initialized
62+
pub fn image_handle() -> NonNull<c_void> {
63+
try_image_handle().unwrap()
64+
}
65+
66+
/// Get the BootServices Pointer.
67+
/// This function also checks if `ExitBootServices` has already been called.
68+
pub fn boot_services() -> Option<NonNull<c_void>> {
69+
if BOOT_SERVICES_FLAG.load(Ordering::Acquire) {
70+
let system_table: NonNull<r_efi::efi::SystemTable> = try_system_table()?.cast();
71+
let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
72+
NonNull::new(boot_services).map(|x| x.cast())
73+
} else {
74+
None
75+
}
76+
}
77+
78+
/// Get the SystemTable Pointer.
79+
/// This function is mostly intended for places where panic is not an option
80+
pub(crate) fn try_system_table() -> Option<NonNull<c_void>> {
81+
NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire))
82+
}
83+
84+
/// Get the SystemHandle Pointer.
85+
/// This function is mostly intended for places where panicking is not an option
86+
pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> {
87+
NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
88+
}
89+
90+
pub(crate) fn disable_boot_services() {
91+
BOOT_SERVICES_FLAG.store(false, Ordering::Release)
92+
}

std/src/os/uefi/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//! Platform-specific extensions to `std` for UEFI.
2+
3+
#![unstable(feature = "uefi_std", issue = "100499")]
4+
#![doc(cfg(target_os = "uefi"))]
5+
6+
pub mod env;
7+
#[path = "../windows/ffi.rs"]
8+
pub mod ffi;

std/src/sys/common/thread_local/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// "static" is for single-threaded platforms where a global static is sufficient.
77

88
cfg_if::cfg_if! {
9-
if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
9+
if #[cfg(any(all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi"))] {
1010
#[doc(hidden)]
1111
mod static_local;
1212
#[doc(hidden)]

std/src/sys/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ cfg_if::cfg_if! {
4747
} else if #[cfg(target_os = "xous")] {
4848
mod xous;
4949
pub use self::xous::*;
50+
} else if #[cfg(target_os = "uefi")] {
51+
mod uefi;
52+
pub use self::uefi::*;
5053
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
5154
mod sgx;
5255
pub use self::sgx::*;
@@ -114,4 +117,5 @@ pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
114117
log_fn(n)
115118
}
116119

120+
#[cfg(not(target_os = "uefi"))]
117121
pub type RawOsError = i32;

std/src/sys/uefi/alloc.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//! Global Allocator for UEFI.
2+
//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
3+
4+
use crate::alloc::{GlobalAlloc, Layout, System};
5+
6+
const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA;
7+
8+
#[stable(feature = "alloc_system_type", since = "1.28.0")]
9+
unsafe impl GlobalAlloc for System {
10+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
11+
// Return null pointer if boot services are not available
12+
if crate::os::uefi::env::boot_services().is_none() {
13+
return crate::ptr::null_mut();
14+
}
15+
16+
// If boot services is valid then SystemTable is not null.
17+
let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
18+
// The caller must ensure non-0 layout
19+
unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
20+
}
21+
22+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
23+
// Do nothing if boot services are not available
24+
if crate::os::uefi::env::boot_services().is_none() {
25+
return;
26+
}
27+
28+
// If boot services is valid then SystemTable is not null.
29+
let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
30+
// The caller must ensure non-0 layout
31+
unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
32+
}
33+
}

0 commit comments

Comments
 (0)