about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-09-27 06:51:43 +0000
committerbors <bors@rust-lang.org>2023-09-27 06:51:43 +0000
commit1a3dd7ea7d929db798b7095d3c25f50b49a52fb4 (patch)
tree69c3f1ea1b4d8aab2e857ca1604cfe6bbdff7d2f /library/std/src
parente86c68aa545fc3cfa5085811590e52011ed1a602 (diff)
parentc8a44b1eaf5aed5cf8e57340f1ac56c9bad08acf (diff)
downloadrust-1a3dd7ea7d929db798b7095d3c25f50b49a52fb4.tar.gz
rust-1a3dd7ea7d929db798b7095d3c25f50b49a52fb4.zip
Auto merge of #3087 - rust-lang:rustup-2023-09-27, r=RalfJung
Automatic sync from rustc
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/io/error.rs8
-rw-r--r--library/std/src/io/mod.rs35
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/uefi/env.rs92
-rw-r--r--library/std/src/os/uefi/mod.rs8
-rw-r--r--library/std/src/os/unix/io/mod.rs11
-rw-r--r--library/std/src/os/windows/io/mod.rs11
-rw-r--r--library/std/src/sys/common/thread_local/mod.rs2
-rw-r--r--library/std/src/sys/mod.rs4
-rw-r--r--library/std/src/sys/uefi/alloc.rs33
-rw-r--r--library/std/src/sys/uefi/env.rs9
-rw-r--r--library/std/src/sys/uefi/helpers.rs141
-rw-r--r--library/std/src/sys/uefi/mod.rs244
-rw-r--r--library/std/src/sys/uefi/os.rs237
-rw-r--r--library/std/src/sys/uefi/path.rs25
-rw-r--r--library/std/src/sys/uefi/tests.rs21
-rw-r--r--library/std/src/sys_common/mod.rs1
18 files changed, 858 insertions, 29 deletions
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index f63142ff01f..5966416e32a 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -1,14 +1,14 @@
 #[cfg(test)]
 mod tests;
 
-#[cfg(target_pointer_width = "64")]
+#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
 mod repr_bitpacked;
-#[cfg(target_pointer_width = "64")]
+#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
 use repr_bitpacked::Repr;
 
-#[cfg(not(target_pointer_width = "64"))]
+#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
 mod repr_unpacked;
-#[cfg(not(target_pointer_width = "64"))]
+#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
 use repr_unpacked::Repr;
 
 use crate::error;
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 7582c7444f0..604b795cd52 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1236,22 +1236,22 @@ impl<'a> IoSliceMut<'a> {
     pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
         // Number of buffers to remove.
         let mut remove = 0;
-        // Total length of all the to be removed buffers.
-        let mut accumulated_len = 0;
+        // Remaining length before reaching n.
+        let mut left = n;
         for buf in bufs.iter() {
-            if accumulated_len + buf.len() > n {
-                break;
-            } else {
-                accumulated_len += buf.len();
+            if let Some(remainder) = left.checked_sub(buf.len()) {
+                left = remainder;
                 remove += 1;
+            } else {
+                break;
             }
         }
 
         *bufs = &mut take(bufs)[remove..];
         if bufs.is_empty() {
-            assert!(n == accumulated_len, "advancing io slices beyond their length");
+            assert!(left == 0, "advancing io slices beyond their length");
         } else {
-            bufs[0].advance(n - accumulated_len)
+            bufs[0].advance(left);
         }
     }
 }
@@ -1379,22 +1379,25 @@ impl<'a> IoSlice<'a> {
     pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
         // Number of buffers to remove.
         let mut remove = 0;
-        // Total length of all the to be removed buffers.
-        let mut accumulated_len = 0;
+        // Remaining length before reaching n. This prevents overflow
+        // that could happen if the length of slices in `bufs` were instead
+        // accumulated. Those slice may be aliased and, if they are large
+        // enough, their added length may overflow a `usize`.
+        let mut left = n;
         for buf in bufs.iter() {
-            if accumulated_len + buf.len() > n {
-                break;
-            } else {
-                accumulated_len += buf.len();
+            if let Some(remainder) = left.checked_sub(buf.len()) {
+                left = remainder;
                 remove += 1;
+            } else {
+                break;
             }
         }
 
         *bufs = &mut take(bufs)[remove..];
         if bufs.is_empty() {
-            assert!(n == accumulated_len, "advancing io slices beyond their length");
+            assert!(left == 0, "advancing io slices beyond their length");
         } else {
-            bufs[0].advance(n - accumulated_len)
+            bufs[0].advance(left);
         }
     }
 }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5e3249655b8..f1f0f8b1653 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -665,6 +665,9 @@ pub use core::{
 )]
 pub use core::concat_bytes;
 
+#[unstable(feature = "cfg_match", issue = "115585")]
+pub use core::cfg_match;
+
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub use core::primitive;
 
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 24d16e64c86..11ad21515fd 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -142,6 +142,8 @@ pub mod solid;
 #[cfg(target_os = "tvos")]
 #[path = "ios/mod.rs"]
 pub(crate) mod tvos;
+#[cfg(target_os = "uefi")]
+pub mod uefi;
 #[cfg(target_os = "vita")]
 pub mod vita;
 #[cfg(target_os = "vxworks")]
diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs
new file mode 100644
index 00000000000..5d082e7c113
--- /dev/null
+++ b/library/std/src/os/uefi/env.rs
@@ -0,0 +1,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)
+}
diff --git a/library/std/src/os/uefi/mod.rs b/library/std/src/os/uefi/mod.rs
new file mode 100644
index 00000000000..8ef05eee1f4
--- /dev/null
+++ b/library/std/src/os/uefi/mod.rs
@@ -0,0 +1,8 @@
+//! Platform-specific extensions to `std` for UEFI.
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+#![doc(cfg(target_os = "uefi"))]
+
+pub mod env;
+#[path = "../windows/ffi.rs"]
+pub mod ffi;
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index c12d89ed637..827278f8b26 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -6,7 +6,8 @@
 //!
 //! This module provides three types for representing file descriptors,
 //! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers. These types reflect the Unix version of [I/O safety].
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Unix.
 //!
 //! | Type               | Analogous to |
 //! | ------------------ | ------------ |
@@ -17,8 +18,8 @@
 //! Like raw pointers, `RawFd` values are primitive values. And in new code,
 //! they should be considered unsafe to do I/O on (analogous to dereferencing
 //! them). Rust did not always provide this guidance, so existing code in the
-//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
-//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe.
+//! Libraries are encouraged to migrate,
 //! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
 //! using to `BorrowedFd` or `OwnedFd` instead.
 //!
@@ -54,6 +55,8 @@
 //! Like boxes, `OwnedFd` values conceptually own the resource they point to,
 //! and free (close) it when they are dropped.
 //!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
 //! ## `/proc/self/mem` and similar OS features
 //!
 //! Some platforms have special files, such as `/proc/self/mem`, which
@@ -74,7 +77,7 @@
 //! necessary to use *sandboxing*, which is outside the scope of `std`.
 //!
 //! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
-//! [I/O safety]: crate::io#io-safety
+//! [io-safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
index 3d4bb96d458..3d3ae387886 100644
--- a/library/std/src/os/windows/io/mod.rs
+++ b/library/std/src/os/windows/io/mod.rs
@@ -6,7 +6,8 @@
 //!
 //! This module provides three types for representing raw handles and sockets
 //! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers. These types reflect the Windows version of [I/O safety].
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Windows.
 //!
 //! | Type                   | Analogous to |
 //! | ---------------------- | ------------ |
@@ -23,8 +24,8 @@
 //! And in new code, they should be considered unsafe to do I/O on (analogous
 //! to dereferencing them). Rust did not always provide this guidance, so
 //! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
-//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
-//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! `RawSocket` usage as unsafe.
+//! Libraries are encouraged to migrate, either by adding `unsafe` to APIs
 //! that dereference `RawHandle` and `RawSocket` values, or by using to
 //! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
 //!
@@ -45,9 +46,11 @@
 //! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
 //! resource they point to, and free (close) it when they are dropped.
 //!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
 //! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
 //! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
-//! [I/O safety]: crate::io#io-safety
+//! [io-safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/sys/common/thread_local/mod.rs b/library/std/src/sys/common/thread_local/mod.rs
index 975509bd412..8b2c839f837 100644
--- a/library/std/src/sys/common/thread_local/mod.rs
+++ b/library/std/src/sys/common/thread_local/mod.rs
@@ -6,7 +6,7 @@
 // "static" is for single-threaded platforms where a global static is sufficient.
 
 cfg_if::cfg_if! {
-    if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
+    if #[cfg(any(all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi"))] {
         #[doc(hidden)]
         mod static_local;
         #[doc(hidden)]
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 457eb782ccc..159ffe7ac96 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -47,6 +47,9 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "xous")] {
         mod xous;
         pub use self::xous::*;
+    } else if #[cfg(target_os = "uefi")] {
+        mod uefi;
+        pub use self::uefi::*;
     } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
         mod sgx;
         pub use self::sgx::*;
@@ -114,4 +117,5 @@ pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
     log_fn(n)
 }
 
+#[cfg(not(target_os = "uefi"))]
 pub type RawOsError = i32;
diff --git a/library/std/src/sys/uefi/alloc.rs b/library/std/src/sys/uefi/alloc.rs
new file mode 100644
index 00000000000..789e3cbd81a
--- /dev/null
+++ b/library/std/src/sys/uefi/alloc.rs
@@ -0,0 +1,33 @@
+//! Global Allocator for UEFI.
+//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // Return null pointer if boot services are not available
+        if crate::os::uefi::env::boot_services().is_none() {
+            return crate::ptr::null_mut();
+        }
+
+        // If boot services is valid then SystemTable is not null.
+        let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
+        // The caller must ensure non-0 layout
+        unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        // Do nothing if boot services are not available
+        if crate::os::uefi::env::boot_services().is_none() {
+            return;
+        }
+
+        // If boot services is valid then SystemTable is not null.
+        let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
+        // The caller must ensure non-0 layout
+        unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
+    }
+}
diff --git a/library/std/src/sys/uefi/env.rs b/library/std/src/sys/uefi/env.rs
new file mode 100644
index 00000000000..c106d5fed3e
--- /dev/null
+++ b/library/std/src/sys/uefi/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "uefi";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = ".efi";
+    pub const EXE_EXTENSION: &str = "efi";
+}
diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs
new file mode 100644
index 00000000000..126661bfc96
--- /dev/null
+++ b/library/std/src/sys/uefi/helpers.rs
@@ -0,0 +1,141 @@
+//! Contains most of the shared UEFI specific stuff. Some of this might be moved to `std::os::uefi`
+//! if needed but no point in adding extra public API when there is not Std support for UEFI in the
+//! first place
+//!
+//! Some Nomenclature
+//! * Protocol:
+//! - Protocols serve to enable communication between separately built modules, including drivers.
+//! - Every protocol has a GUID associated with it. The GUID serves as the name for the protocol.
+//! - Protocols are produced and consumed.
+//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
+
+use r_efi::efi::{self, Guid};
+
+use crate::mem::{size_of, MaybeUninit};
+use crate::os::uefi;
+use crate::ptr::NonNull;
+use crate::{
+    io::{self, const_io_error},
+    os::uefi::env::boot_services,
+};
+
+const BOOT_SERVICES_UNAVAILABLE: io::Error =
+    const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
+
+/// Locate Handles with a particular Protocol GUID
+/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`
+///
+/// Returns an array of [Handles](r_efi::efi::Handle) that support a specified protocol.
+pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ffi::c_void>>> {
+    fn inner(
+        guid: &mut Guid,
+        boot_services: NonNull<r_efi::efi::BootServices>,
+        buf_size: &mut usize,
+        buf: *mut r_efi::efi::Handle,
+    ) -> io::Result<()> {
+        let r = unsafe {
+            ((*boot_services.as_ptr()).locate_handle)(
+                r_efi::efi::BY_PROTOCOL,
+                guid,
+                crate::ptr::null_mut(),
+                buf_size,
+                buf,
+            )
+        };
+
+        if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+    }
+
+    let boot_services = boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+    let mut buf_len = 0usize;
+
+    // This should always fail since the size of buffer is 0. This call should update the buf_len
+    // variable with the required buffer length
+    match inner(&mut guid, boot_services, &mut buf_len, crate::ptr::null_mut()) {
+        Ok(()) => unreachable!(),
+        Err(e) => match e.kind() {
+            io::ErrorKind::FileTooLarge => {}
+            _ => return Err(e),
+        },
+    }
+
+    // The returned buf_len is in bytes
+    assert_eq!(buf_len % size_of::<r_efi::efi::Handle>(), 0);
+    let num_of_handles = buf_len / size_of::<r_efi::efi::Handle>();
+    let mut buf: Vec<r_efi::efi::Handle> = Vec::with_capacity(num_of_handles);
+    match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) {
+        Ok(()) => {
+            // This is safe because the call will succeed only if buf_len >= required length.
+            // Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written
+            unsafe { buf.set_len(num_of_handles) };
+            Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect())
+        }
+        Err(e) => Err(e),
+    }
+}
+
+/// Open Protocol on a handle.
+/// Internally just a call to `EFI_BOOT_SERVICES.OpenProtocol()`.
+///
+/// Queries a handle to determine if it supports a specified protocol. If the protocol is
+/// supported by the handle, it opens the protocol on behalf of the calling agent.
+pub(crate) fn open_protocol<T>(
+    handle: NonNull<crate::ffi::c_void>,
+    mut protocol_guid: Guid,
+) -> io::Result<NonNull<T>> {
+    let boot_services: NonNull<efi::BootServices> =
+        boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+    let system_handle = uefi::env::image_handle();
+    let mut protocol: MaybeUninit<*mut T> = MaybeUninit::uninit();
+
+    let r = unsafe {
+        ((*boot_services.as_ptr()).open_protocol)(
+            handle.as_ptr(),
+            &mut protocol_guid,
+            protocol.as_mut_ptr().cast(),
+            system_handle.as_ptr(),
+            crate::ptr::null_mut(),
+            r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL,
+        )
+    };
+
+    if r.is_error() {
+        Err(crate::io::Error::from_raw_os_error(r.as_usize()))
+    } else {
+        NonNull::new(unsafe { protocol.assume_init() })
+            .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+    }
+}
+
+pub(crate) fn create_event(
+    signal: u32,
+    tpl: efi::Tpl,
+    handler: Option<efi::EventNotify>,
+    context: *mut crate::ffi::c_void,
+) -> io::Result<NonNull<crate::ffi::c_void>> {
+    let boot_services: NonNull<efi::BootServices> =
+        boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+    let mut event: r_efi::efi::Event = crate::ptr::null_mut();
+    let r = unsafe {
+        let create_event = (*boot_services.as_ptr()).create_event;
+        (create_event)(signal, tpl, handler, context, &mut event)
+    };
+    if r.is_error() {
+        Err(crate::io::Error::from_raw_os_error(r.as_usize()))
+    } else {
+        NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+    }
+}
+
+/// # SAFETY
+/// - The supplied event must be valid
+pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result<()> {
+    let boot_services: NonNull<efi::BootServices> =
+        boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+    let r = unsafe {
+        let close_event = (*boot_services.as_ptr()).close_event;
+        (close_event)(evt.as_ptr())
+    };
+
+    if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+}
diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs
new file mode 100644
index 00000000000..9a10395af8e
--- /dev/null
+++ b/library/std/src/sys/uefi/mod.rs
@@ -0,0 +1,244 @@
+//! Platform-specific extensions to `std` for UEFI platforms.
+//!
+//! Provides access to platform-level information on UEFI platforms, and
+//! exposes UEFI-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod env;
+#[path = "../unsupported/fs.rs"]
+pub mod fs;
+#[path = "../unsupported/io.rs"]
+pub mod io;
+#[path = "../unsupported/locks/mod.rs"]
+pub mod locks;
+#[path = "../unsupported/net.rs"]
+pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
+pub mod os;
+#[path = "../windows/os_str.rs"]
+pub mod os_str;
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+#[path = "../unsupported/stdio.rs"]
+pub mod stdio;
+#[path = "../unsupported/thread.rs"]
+pub mod thread;
+#[path = "../unsupported/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../unsupported/thread_parking.rs"]
+pub mod thread_parking;
+#[path = "../unsupported/time.rs"]
+pub mod time;
+
+mod helpers;
+
+#[cfg(test)]
+mod tests;
+
+pub type RawOsError = usize;
+
+use crate::io as std_io;
+use crate::os::uefi;
+use crate::ptr::NonNull;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+
+pub mod memchr {
+    pub use core::slice::memchr::{memchr, memrchr};
+}
+
+static EXIT_BOOT_SERVICE_EVENT: AtomicPtr<crate::ffi::c_void> =
+    AtomicPtr::new(crate::ptr::null_mut());
+
+/// # SAFETY
+/// - must be called only once during runtime initialization.
+/// - argc must be 2.
+/// - argv must be &[Handle, *mut SystemTable].
+pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
+    assert_eq!(argc, 2);
+    let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() };
+    let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() };
+    unsafe { uefi::env::init_globals(image_handle, system_table) };
+
+    // Register exit boot services handler
+    match helpers::create_event(
+        r_efi::efi::EVT_SIGNAL_EXIT_BOOT_SERVICES,
+        r_efi::efi::TPL_NOTIFY,
+        Some(exit_boot_service_handler),
+        crate::ptr::null_mut(),
+    ) {
+        Ok(x) => {
+            if EXIT_BOOT_SERVICE_EVENT
+                .compare_exchange(
+                    crate::ptr::null_mut(),
+                    x.as_ptr(),
+                    Ordering::Release,
+                    Ordering::Acquire,
+                )
+                .is_err()
+            {
+                abort_internal();
+            };
+        }
+        Err(_) => abort_internal(),
+    }
+}
+
+/// # SAFETY
+/// this is not guaranteed to run, for example when the program aborts.
+/// - must be called only once during runtime cleanup.
+pub unsafe fn cleanup() {
+    if let Some(exit_boot_service_event) =
+        NonNull::new(EXIT_BOOT_SERVICE_EVENT.swap(crate::ptr::null_mut(), Ordering::Acquire))
+    {
+        let _ = unsafe { helpers::close_event(exit_boot_service_event) };
+    }
+}
+
+#[inline]
+pub const fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+#[inline]
+pub const fn unsupported_err() -> std_io::Error {
+    std_io::const_io_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",)
+}
+
+pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind {
+    use crate::io::ErrorKind;
+    use r_efi::efi::Status;
+
+    match r_efi::efi::Status::from_usize(code) {
+        Status::ALREADY_STARTED
+        | Status::COMPROMISED_DATA
+        | Status::CONNECTION_FIN
+        | Status::CRC_ERROR
+        | Status::DEVICE_ERROR
+        | Status::END_OF_MEDIA
+        | Status::HTTP_ERROR
+        | Status::ICMP_ERROR
+        | Status::INCOMPATIBLE_VERSION
+        | Status::LOAD_ERROR
+        | Status::MEDIA_CHANGED
+        | Status::NO_MAPPING
+        | Status::NO_MEDIA
+        | Status::NOT_STARTED
+        | Status::PROTOCOL_ERROR
+        | Status::PROTOCOL_UNREACHABLE
+        | Status::TFTP_ERROR
+        | Status::VOLUME_CORRUPTED => ErrorKind::Other,
+        Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => ErrorKind::InvalidData,
+        Status::ABORTED => ErrorKind::ConnectionAborted,
+        Status::ACCESS_DENIED => ErrorKind::PermissionDenied,
+        Status::BUFFER_TOO_SMALL => ErrorKind::FileTooLarge,
+        Status::CONNECTION_REFUSED => ErrorKind::ConnectionRefused,
+        Status::CONNECTION_RESET => ErrorKind::ConnectionReset,
+        Status::END_OF_FILE => ErrorKind::UnexpectedEof,
+        Status::HOST_UNREACHABLE => ErrorKind::HostUnreachable,
+        Status::INVALID_PARAMETER => ErrorKind::InvalidInput,
+        Status::IP_ADDRESS_CONFLICT => ErrorKind::AddrInUse,
+        Status::NETWORK_UNREACHABLE => ErrorKind::NetworkUnreachable,
+        Status::NO_RESPONSE => ErrorKind::HostUnreachable,
+        Status::NOT_FOUND => ErrorKind::NotFound,
+        Status::NOT_READY => ErrorKind::ResourceBusy,
+        Status::OUT_OF_RESOURCES => ErrorKind::OutOfMemory,
+        Status::SECURITY_VIOLATION => ErrorKind::PermissionDenied,
+        Status::TIMEOUT => ErrorKind::TimedOut,
+        Status::UNSUPPORTED => ErrorKind::Unsupported,
+        Status::VOLUME_FULL => ErrorKind::StorageFull,
+        Status::WRITE_PROTECTED => ErrorKind::ReadOnlyFilesystem,
+        _ => ErrorKind::Uncategorized,
+    }
+}
+
+pub fn abort_internal() -> ! {
+    if let Some(exit_boot_service_event) =
+        NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire))
+    {
+        let _ = unsafe { helpers::close_event(exit_boot_service_event) };
+    }
+
+    if let (Some(boot_services), Some(handle)) =
+        (uefi::env::boot_services(), uefi::env::try_image_handle())
+    {
+        let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+        let _ = unsafe {
+            ((*boot_services.as_ptr()).exit)(
+                handle.as_ptr(),
+                r_efi::efi::Status::ABORTED,
+                0,
+                crate::ptr::null_mut(),
+            )
+        };
+    }
+
+    // In case SystemTable and ImageHandle cannot be reached, use `core::intrinsics::abort`
+    core::intrinsics::abort();
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub extern "C" fn __rust_abort() {
+    abort_internal();
+}
+
+#[inline]
+pub fn hashmap_random_keys() -> (u64, u64) {
+    get_random().unwrap()
+}
+
+fn get_random() -> Option<(u64, u64)> {
+    use r_efi::protocols::rng;
+
+    let mut buf = [0u8; 16];
+    let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?;
+    for handle in handles {
+        if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
+            let r = unsafe {
+                ((*protocol.as_ptr()).get_rng)(
+                    protocol.as_ptr(),
+                    crate::ptr::null_mut(),
+                    buf.len(),
+                    buf.as_mut_ptr(),
+                )
+            };
+            if r.is_error() {
+                continue;
+            } else {
+                return Some((
+                    u64::from_le_bytes(buf[..8].try_into().ok()?),
+                    u64::from_le_bytes(buf[8..].try_into().ok()?),
+                ));
+            }
+        }
+    }
+    None
+}
+
+/// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled
+extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) {
+    uefi::env::disable_boot_services();
+}
+
+pub fn is_interrupted(_code: RawOsError) -> bool {
+    false
+}
diff --git a/library/std/src/sys/uefi/os.rs b/library/std/src/sys/uefi/os.rs
new file mode 100644
index 00000000000..e6693db68e6
--- /dev/null
+++ b/library/std/src/sys/uefi/os.rs
@@ -0,0 +1,237 @@
+use super::{unsupported, RawOsError};
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::os::uefi;
+use crate::path::{self, PathBuf};
+use crate::ptr::NonNull;
+use r_efi::efi::Status;
+
+pub fn errno() -> RawOsError {
+    0
+}
+
+pub fn error_string(errno: RawOsError) -> String {
+    // Keep the List in Alphabetical Order
+    // The Messages are taken from UEFI Specification Appendix D - Status Codes
+    match r_efi::efi::Status::from_usize(errno) {
+        Status::ABORTED => "The operation was aborted.".to_owned(),
+        Status::ACCESS_DENIED => "Access was denied.".to_owned(),
+        Status::ALREADY_STARTED => "The protocol has already been started.".to_owned(),
+        Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.".to_owned(),
+        Status::BUFFER_TOO_SMALL => {
+                "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.".to_owned()
+        }
+        Status::COMPROMISED_DATA => {
+                "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.".to_owned()
+        }
+        Status::CONNECTION_FIN => {
+                "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.".to_owned()
+        }
+        Status::CONNECTION_REFUSED => {
+                "The receiving or transmission operation fails because this connection is refused.".to_owned()
+        }
+        Status::CONNECTION_RESET => {
+                "The connect fails because the connection is reset either by instance itself or the communication peer.".to_owned()
+        }
+        Status::CRC_ERROR => "A CRC error was detected.".to_owned(),
+        Status::DEVICE_ERROR =>             "The physical device reported an error while attempting the operation.".to_owned()
+        ,
+        Status::END_OF_FILE => {
+            "The end of the file was reached.".to_owned()
+        }
+        Status::END_OF_MEDIA => {
+            "Beginning or end of media was reached".to_owned()
+        }
+        Status::HOST_UNREACHABLE => {
+            "The remote host is not reachable.".to_owned()
+        }
+        Status::HTTP_ERROR => {
+            "A HTTP error occurred during the network operation.".to_owned()
+        }
+        Status::ICMP_ERROR => {
+                "An ICMP error occurred during the network operation.".to_owned()
+        }
+        Status::INCOMPATIBLE_VERSION => {
+                "The function encountered an internal version that was incompatible with a version requested by the caller.".to_owned()
+        }
+        Status::INVALID_LANGUAGE => {
+            "The language specified was invalid.".to_owned()
+        }
+        Status::INVALID_PARAMETER => {
+            "A parameter was incorrect.".to_owned()
+        }
+        Status::IP_ADDRESS_CONFLICT => {
+            "There is an address conflict address allocation".to_owned()
+        }
+        Status::LOAD_ERROR => {
+            "The image failed to load.".to_owned()
+        }
+        Status::MEDIA_CHANGED => {
+                "The medium in the device has changed since the last access.".to_owned()
+        }
+        Status::NETWORK_UNREACHABLE => {
+                "The network containing the remote host is not reachable.".to_owned()
+        }
+        Status::NO_MAPPING => {
+            "A mapping to a device does not exist.".to_owned()
+        }
+        Status::NO_MEDIA => {
+                "The device does not contain any medium to perform the operation.".to_owned()
+        }
+        Status::NO_RESPONSE => {
+                "The server was not found or did not respond to the request.".to_owned()
+        }
+        Status::NOT_FOUND => "The item was not found.".to_owned(),
+        Status::NOT_READY => {
+            "There is no data pending upon return.".to_owned()
+        }
+        Status::NOT_STARTED => {
+            "The protocol has not been started.".to_owned()
+        }
+        Status::OUT_OF_RESOURCES => {
+            "A resource has run out.".to_owned()
+        }
+        Status::PROTOCOL_ERROR => {
+                "A protocol error occurred during the network operation.".to_owned()
+        }
+        Status::PROTOCOL_UNREACHABLE => {
+            "An ICMP protocol unreachable error is received.".to_owned()
+        }
+        Status::SECURITY_VIOLATION => {
+                "The function was not performed due to a security violation.".to_owned()
+        }
+        Status::TFTP_ERROR => {
+            "A TFTP error occurred during the network operation.".to_owned()
+        }
+        Status::TIMEOUT => "The timeout time expired.".to_owned(),
+        Status::UNSUPPORTED => {
+            "The operation is not supported.".to_owned()
+        }
+        Status::VOLUME_FULL => {
+            "There is no more space on the file system.".to_owned()
+        }
+        Status::VOLUME_CORRUPTED => {
+                "An inconstancy was detected on the file system causing the operating to fail.".to_owned()
+        }
+        Status::WRITE_PROTECTED => {
+            "The device cannot be written to.".to_owned()
+        }
+        _ => format!("Status: {}", errno),
+    }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        self.0
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on this platform yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub struct Env(!);
+
+impl Env {
+    // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+    pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+        let Self(inner) = self;
+        match *inner {}
+    }
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        self.0
+    }
+}
+
+impl fmt::Debug for Env {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self(inner) = self;
+        match *inner {}
+    }
+}
+
+pub fn env() -> Env {
+    panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+    None
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(code: i32) -> ! {
+    if let (Some(boot_services), Some(handle)) =
+        (uefi::env::boot_services(), uefi::env::try_image_handle())
+    {
+        let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+        let _ = unsafe {
+            ((*boot_services.as_ptr()).exit)(
+                handle.as_ptr(),
+                Status::from_usize(code as usize),
+                0,
+                crate::ptr::null_mut(),
+            )
+        };
+    }
+    crate::intrinsics::abort()
+}
+
+pub fn getpid() -> u32 {
+    panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/uefi/path.rs b/library/std/src/sys/uefi/path.rs
new file mode 100644
index 00000000000..106682eee56
--- /dev/null
+++ b/library/std/src/sys/uefi/path.rs
@@ -0,0 +1,25 @@
+use super::unsupported;
+use crate::ffi::OsStr;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'\\'
+}
+
+pub fn parse_prefix(_p: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
diff --git a/library/std/src/sys/uefi/tests.rs b/library/std/src/sys/uefi/tests.rs
new file mode 100644
index 00000000000..8806eda3ac0
--- /dev/null
+++ b/library/std/src/sys/uefi/tests.rs
@@ -0,0 +1,21 @@
+use super::alloc::*;
+
+#[test]
+fn align() {
+    // UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
+    // statically verified.
+    assert_eq!(POOL_ALIGNMENT, 8);
+
+    // Loop over allocation-request sizes from 0-256 and alignments from 1-128, and verify
+    // that in case of overalignment there is at least space for one additional pointer to
+    // store in the allocation.
+    for i in 0..256 {
+        for j in &[1, 2, 4, 8, 16, 32, 64, 128] {
+            if *j <= 8 {
+                assert_eq!(align_size(i, *j), i);
+            } else {
+                assert!(align_size(i, *j) > i + std::mem::size_of::<*mut ()>());
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index f7d82175063..e18638f2a5f 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -44,6 +44,7 @@ cfg_if::cfg_if! {
 
 cfg_if::cfg_if! {
     if #[cfg(any(target_os = "l4re",
+                 target_os = "uefi",
                  feature = "restricted-std",
                  all(target_family = "wasm", not(target_os = "emscripten")),
                  target_os = "xous",