about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.nlsp-settings/rust_analyzer.json3
-rw-r--r--Cargo.lock23
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs35
-rw-r--r--compiler/rustc_target/src/spec/uefi_msvc_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs3
-rw-r--r--library/panic_abort/src/lib.rs1
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/build.rs3
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/mod.rs2
-rw-r--r--library/std/src/os/uefi/env.rs54
-rw-r--r--library/std/src/os/uefi/mod.rs7
-rw-r--r--library/std/src/sys/common/thread_local/mod.rs2
-rw-r--r--library/std/src/sys/mod.rs3
-rw-r--r--library/std/src/sys/uefi/alloc.rs32
-rw-r--r--library/std/src/sys/uefi/common.rs269
-rw-r--r--library/std/src/sys/uefi/env.rs9
-rw-r--r--library/std/src/sys/uefi/mod.rs155
-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.rs2
-rw-r--r--src/bootstrap/config.rs6
-rw-r--r--src/doc/rustc/src/platform-support/unknown-uefi.md72
-rw-r--r--src/tools/tidy/src/deps.rs3
24 files changed, 718 insertions, 18 deletions
diff --git a/.nlsp-settings/rust_analyzer.json b/.nlsp-settings/rust_analyzer.json
new file mode 100644
index 00000000000..eddf84afb2a
--- /dev/null
+++ b/.nlsp-settings/rust_analyzer.json
@@ -0,0 +1,3 @@
+{
+  "rust-analyzer.cargo.target": "x86_64-unknown-uefi"
+}
diff --git a/Cargo.lock b/Cargo.lock
index d9aaedb8544..f84387f30be 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3007,6 +3007,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "r-efi"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e7345c622833c6745e7b027a28aa95618813dc1f3c3de396206410267dce6f3"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "r-efi-alloc"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
+dependencies = [
+ "compiler_builtins",
+ "r-efi",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "rand"
 version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5012,6 +5033,8 @@ dependencies = [
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
+ "r-efi",
+ "r-efi-alloc",
  "rand",
  "rand_xorshift",
  "rustc-demangle",
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index cd19885faa0..4753f125540 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -420,9 +420,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         rust_main_def_id: DefId,
         entry_type: EntryFnType,
     ) -> Bx::Function {
-        // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
-        // depending on whether the target needs `argc` and `argv` to be passed in.
-        let llfty = if cx.sess().target.main_needs_argc_argv {
+        // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
+        // `Status efi_main(Handle hd, SystemTable *st)` depending on the target.
+        let llfty = if cx.sess().target.os.contains("uefi") {
+            cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
+        } else if cx.sess().target.main_needs_argc_argv {
             cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
         } else {
             cx.type_func(&[], cx.type_int())
@@ -485,8 +487,12 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         };
 
         let result = bx.call(start_ty, None, None, start_fn, &args, None);
-        let cast = bx.intcast(result, cx.type_int(), true);
-        bx.ret(cast);
+        if cx.sess().target.os.contains("uefi") {
+            bx.ret(result);
+        } else {
+            let cast = bx.intcast(result, cx.type_int(), true);
+            bx.ret(cast);
+        }
 
         llfn
     }
@@ -497,7 +503,18 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
     bx: &mut Bx,
 ) -> (Bx::Value, Bx::Value) {
-    if cx.sess().target.main_needs_argc_argv {
+    if cx.sess().target.os.contains("uefi") {
+        // Params for UEFI
+        let param_handle = bx.get_param(0);
+        let param_system_table = bx.get_param(1);
+        let arg_argc = bx.const_int(cx.type_isize(), 2);
+        let arg_argv = bx.alloca(cx.type_array(cx.type_i8p(), 2), Align::ONE);
+        bx.store(param_handle, arg_argv, Align::ONE);
+        let arg_argv_el1 =
+            bx.gep(cx.type_ptr_to(cx.type_i8()), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
+        bx.store(param_system_table, arg_argv_el1, Align::ONE);
+        (arg_argc, arg_argv)
+    } else if cx.sess().target.main_needs_argc_argv {
         // Params from native `main()` used as args for rust start function
         let param_argc = bx.get_param(0);
         let param_argv = bx.get_param(1);
@@ -549,7 +566,11 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
         use rustc_middle::middle::dependency_format::Linkage;
         list.iter().any(|&linkage| linkage == Linkage::Dynamic)
     });
-    if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
+    if any_dynamic_crate {
+        None
+    } else {
+        tcx.allocator_kind(())
+    }
 }
 
 pub fn codegen_crate<B: ExtraBackendMethods>(
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index 8968d3c8fc1..a50a55ad7e0 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -46,6 +46,7 @@ pub fn opts() -> TargetOptions {
         stack_probes: StackProbeType::Call,
         singlethread: true,
         linker: Some("rust-lld".into()),
+        entry_name: "efi_main".into(),
         ..base
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
index 67664a74710..41ba768068a 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
@@ -5,13 +5,14 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::Target;
+use crate::{abi::call::Conv, spec::Target};
 
 pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
     base.cpu = "x86-64".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(64);
+    base.entry_abi = Conv::X86_64Win64;
 
     // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to
     // enable these CPU features explicitly before their first use, otherwise their instructions
diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index d675696f13f..bc0d7287be5 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -45,6 +45,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
         } else if #[cfg(any(target_os = "hermit",
                             all(target_vendor = "fortanix", target_env = "sgx"),
                             target_os = "xous"
+                            target_os = "uefi",
         ))] {
             unsafe fn abort() -> ! {
                 // call std::sys::abort_internal
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index e8f642586cd..1908dfaa33d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -48,6 +48,10 @@ hermit-abi = { version = "0.3.2", features = ['rustc-dep-of-std'], public = true
 [target.'cfg(target_os = "wasi")'.dependencies]
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
 
+[target.'cfg(target_os = "uefi")'.dependencies]
+r-efi = { version = "4.1.0", features = ['rustc-dep-of-std', 'efiapi']}
+r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std']}
+
 [features]
 backtrace = [
   "gimli-symbolize",
diff --git a/library/std/build.rs b/library/std/build.rs
index e5509504b84..1c32b425650 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -39,6 +39,7 @@ fn main() {
         || target.contains("nto")
         || target.contains("xous")
         || target.contains("hurd")
+        || target.contains("uefi")
         // See src/bootstrap/synthetic_targets.rs
         || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
     {
@@ -51,7 +52,7 @@ fn main() {
         // - mipsel-sony-psp
         // - nvptx64-nvidia-cuda
         // - arch=avr
-        // - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
+        // - tvos (aarch64-apple-tvos, x86_64-apple-tvos)
         // - JSON targets
         // - Any new targets that have not been explicitly added above.
         println!("cargo:rustc-cfg=feature=\"restricted-std\"");
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5e3249655b8..b572347019c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -263,7 +263,6 @@
 #![cfg_attr(target_os = "xous", feature(slice_ptr_len))]
 //
 // Language features:
-// tidy-alphabetical-start
 #![feature(alloc_error_handler)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
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..479ff5f6975
--- /dev/null
+++ b/library/std/src/os/uefi/env.rs
@@ -0,0 +1,54 @@
+//! UEFI-specific extensions to the primitives in `std::env` module
+
+use crate::ffi::c_void;
+use crate::ptr::NonNull;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sync::OnceLock;
+
+// Position 0 = SystemTable
+// Position 1 = ImageHandle
+static GLOBALS: OnceLock<(AtomicPtr<c_void>, AtomicPtr<c_void>)> = OnceLock::new();
+
+/// 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.
+/// 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.
+///
+/// This function must not be called more than once.
+#[unstable(feature = "uefi_std", issue = "100499")]
+pub unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
+    GLOBALS.set((AtomicPtr::new(system_table.as_ptr()), AtomicPtr::new(handle.as_ptr()))).unwrap()
+}
+
+/// Get the SystemTable Pointer.
+/// Note: This function panics if the System Table and Image Handle is Not initialized
+#[unstable(feature = "uefi_std", issue = "100499")]
+pub fn system_table() -> NonNull<c_void> {
+    try_system_table().unwrap()
+}
+
+/// Get the SystemHandle Pointer.
+/// Note: This function panics if the System Table and Image Handle is Not initialized
+#[unstable(feature = "uefi_std", issue = "100499")]
+pub fn image_handle() -> NonNull<c_void> {
+    try_image_handle().unwrap()
+}
+
+/// 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<crate::ffi::c_void>> {
+    NonNull::new(GLOBALS.get()?.0.load(Ordering::Acquire))
+}
+
+/// Get the SystemHandle Pointer.
+/// This function is mostly intended for places where panic is not an option
+pub(crate) fn try_image_handle() -> Option<NonNull<crate::ffi::c_void>> {
+    NonNull::new(GLOBALS.get()?.1.load(Ordering::Acquire))
+}
diff --git a/library/std/src/os/uefi/mod.rs b/library/std/src/os/uefi/mod.rs
new file mode 100644
index 00000000000..fc0468f25fc
--- /dev/null
+++ b/library/std/src/os/uefi/mod.rs
@@ -0,0 +1,7 @@
+//! Platform-specific extensions to `std` for UEFI.
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+
+pub mod env;
+#[path = "../windows/ffi.rs"]
+pub mod ffi;
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..a03501e6a13 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::*;
diff --git a/library/std/src/sys/uefi/alloc.rs b/library/std/src/sys/uefi/alloc.rs
new file mode 100644
index 00000000000..6a14ee76e92
--- /dev/null
+++ b/library/std/src/sys/uefi/alloc.rs
@@ -0,0 +1,32 @@
+//! Global Allocator for UEFI.
+//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
+
+use crate::alloc::{handle_alloc_error, 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 {
+        let system_table = match crate::os::uefi::env::try_system_table() {
+            None => return crate::ptr::null_mut(),
+            Some(x) => x.as_ptr() as *mut _,
+        };
+
+        if layout.size() > 0 {
+            unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
+        } else {
+            layout.dangling().as_ptr()
+        }
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        let system_table = match crate::os::uefi::env::try_system_table() {
+            None => handle_alloc_error(layout),
+            Some(x) => x.as_ptr() as *mut _,
+        };
+        if layout.size() > 0 {
+            unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
+        }
+    }
+}
diff --git a/library/std/src/sys/uefi/common.rs b/library/std/src/sys/uefi/common.rs
new file mode 100644
index 00000000000..6316a74d367
--- /dev/null
+++ b/library/std/src/sys/uefi/common.rs
@@ -0,0 +1,269 @@
+//! 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
+
+use r_efi::efi::Guid;
+
+use crate::io::{self, const_io_error};
+use crate::mem::MaybeUninit;
+use crate::os::uefi;
+use crate::ptr::NonNull;
+
+// Locate handles with a particular protocol GUID
+/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`
+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(status_to_io_error(r)) } else { Ok(()) }
+    }
+
+    let boot_services = boot_services();
+    let mut buf_len = 0usize;
+
+    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
+    let mut buf: Vec<r_efi::efi::Handle> =
+        Vec::with_capacity(buf_len / crate::mem::size_of::<r_efi::efi::Handle>());
+    match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) {
+        Ok(()) => {
+            // SAFETY: 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(buf_len / crate::mem::size_of::<r_efi::efi::Handle>()) };
+            Ok(buf.iter().filter_map(|x| NonNull::new(*x)).collect())
+        }
+        Err(e) => Err(e),
+    }
+}
+
+/// Open Protocol on a handle
+/// Implemented using `EFI_BOOT_SERVICES.OpenProtocol()`
+pub(crate) fn open_protocol<T>(
+    handle: NonNull<crate::ffi::c_void>,
+    mut protocol_guid: Guid,
+) -> io::Result<NonNull<T>> {
+    let boot_services = boot_services();
+    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(status_to_io_error(r))
+    } else {
+        NonNull::new(unsafe { protocol.assume_init() })
+            .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+    }
+}
+
+pub(crate) fn status_to_io_error(s: r_efi::efi::Status) -> io::Error {
+    use io::ErrorKind;
+    use r_efi::efi::Status;
+
+    // Keep the List in Alphabetical Order
+    // The Messages are taken from UEFI Specification Appendix D - Status Codes
+    match s {
+        Status::ABORTED => {
+            const_io_error!(ErrorKind::ConnectionAborted, "The operation was aborted.")
+        }
+        Status::ACCESS_DENIED => {
+            const_io_error!(ErrorKind::PermissionDenied, "Access was denied.")
+        }
+        Status::ALREADY_STARTED => {
+            const_io_error!(ErrorKind::Other, "The protocol has already been started.")
+        }
+        Status::BAD_BUFFER_SIZE => {
+            const_io_error!(
+                ErrorKind::InvalidData,
+                "The buffer was not the proper size for the request."
+            )
+        }
+        Status::BUFFER_TOO_SMALL => {
+            const_io_error!(
+                ErrorKind::FileTooLarge,
+                "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."
+            )
+        }
+        Status::COMPROMISED_DATA => {
+            const_io_error!(
+                ErrorKind::Other,
+                "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status."
+            )
+        }
+        Status::CONNECTION_FIN => {
+            const_io_error!(
+                ErrorKind::Other,
+                "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."
+            )
+        }
+        Status::CONNECTION_REFUSED => {
+            const_io_error!(
+                ErrorKind::ConnectionRefused,
+                "The receiving or transmission operation fails because this connection is refused."
+            )
+        }
+        Status::CONNECTION_RESET => {
+            const_io_error!(
+                ErrorKind::ConnectionReset,
+                "The connect fails because the connection is reset either by instance itself or the communication peer."
+            )
+        }
+        Status::CRC_ERROR => const_io_error!(ErrorKind::Other, "A CRC error was detected."),
+        Status::DEVICE_ERROR => const_io_error!(
+            ErrorKind::Other,
+            "The physical device reported an error while attempting the operation."
+        ),
+        Status::END_OF_FILE => {
+            const_io_error!(ErrorKind::UnexpectedEof, "The end of the file was reached.")
+        }
+        Status::END_OF_MEDIA => {
+            const_io_error!(ErrorKind::Other, "Beginning or end of media was reached")
+        }
+        Status::HOST_UNREACHABLE => {
+            const_io_error!(ErrorKind::HostUnreachable, "The remote host is not reachable.")
+        }
+        Status::HTTP_ERROR => {
+            const_io_error!(ErrorKind::Other, "A HTTP error occurred during the network operation.")
+        }
+        Status::ICMP_ERROR => {
+            const_io_error!(
+                ErrorKind::Other,
+                "An ICMP error occurred during the network operation."
+            )
+        }
+        Status::INCOMPATIBLE_VERSION => {
+            const_io_error!(
+                ErrorKind::Other,
+                "The function encountered an internal version that was incompatible with a version requested by the caller."
+            )
+        }
+        Status::INVALID_LANGUAGE => {
+            const_io_error!(ErrorKind::InvalidData, "The language specified was invalid.")
+        }
+        Status::INVALID_PARAMETER => {
+            const_io_error!(ErrorKind::InvalidInput, "A parameter was incorrect.")
+        }
+        Status::IP_ADDRESS_CONFLICT => {
+            const_io_error!(ErrorKind::AddrInUse, "There is an address conflict address allocation")
+        }
+        Status::LOAD_ERROR => {
+            const_io_error!(ErrorKind::Other, "The image failed to load.")
+        }
+        Status::MEDIA_CHANGED => {
+            const_io_error!(
+                ErrorKind::Other,
+                "The medium in the device has changed since the last access."
+            )
+        }
+        Status::NETWORK_UNREACHABLE => {
+            const_io_error!(
+                ErrorKind::NetworkUnreachable,
+                "The network containing the remote host is not reachable."
+            )
+        }
+        Status::NO_MAPPING => {
+            const_io_error!(ErrorKind::Other, "A mapping to a device does not exist.")
+        }
+        Status::NO_MEDIA => {
+            const_io_error!(
+                ErrorKind::Other,
+                "The device does not contain any medium to perform the operation."
+            )
+        }
+        Status::NO_RESPONSE => {
+            const_io_error!(
+                ErrorKind::HostUnreachable,
+                "The server was not found or did not respond to the request."
+            )
+        }
+        Status::NOT_FOUND => const_io_error!(ErrorKind::NotFound, "The item was not found."),
+        Status::NOT_READY => {
+            const_io_error!(ErrorKind::ResourceBusy, "There is no data pending upon return.")
+        }
+        Status::NOT_STARTED => {
+            const_io_error!(ErrorKind::Other, "The protocol has not been started.")
+        }
+        Status::OUT_OF_RESOURCES => {
+            const_io_error!(ErrorKind::OutOfMemory, "A resource has run out.")
+        }
+        Status::PROTOCOL_ERROR => {
+            const_io_error!(
+                ErrorKind::Other,
+                "A protocol error occurred during the network operation."
+            )
+        }
+        Status::PROTOCOL_UNREACHABLE => {
+            const_io_error!(ErrorKind::Other, "An ICMP protocol unreachable error is received.")
+        }
+        Status::SECURITY_VIOLATION => {
+            const_io_error!(
+                ErrorKind::PermissionDenied,
+                "The function was not performed due to a security violation."
+            )
+        }
+        Status::TFTP_ERROR => {
+            const_io_error!(ErrorKind::Other, "A TFTP error occurred during the network operation.")
+        }
+        Status::TIMEOUT => const_io_error!(ErrorKind::TimedOut, "The timeout time expired."),
+        Status::UNSUPPORTED => {
+            const_io_error!(ErrorKind::Unsupported, "The operation is not supported.")
+        }
+        Status::VOLUME_FULL => {
+            const_io_error!(ErrorKind::StorageFull, "There is no more space on the file system.")
+        }
+        Status::VOLUME_CORRUPTED => {
+            const_io_error!(
+                ErrorKind::Other,
+                "An inconstancy was detected on the file system causing the operating to fail."
+            )
+        }
+        Status::WRITE_PROTECTED => {
+            const_io_error!(ErrorKind::ReadOnlyFilesystem, "The device cannot be written to.")
+        }
+        _ => io::Error::new(ErrorKind::Uncategorized, format!("Status: {}", s.as_usize())),
+    }
+}
+
+/// Get the BootServices Pointer.
+pub(crate) fn boot_services() -> NonNull<r_efi::efi::BootServices> {
+    let system_table: NonNull<r_efi::efi::SystemTable> = uefi::env::system_table().cast();
+    let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
+    NonNull::new(boot_services).unwrap()
+}
+/// Get the BootServices Pointer.
+/// This function is mostly intended for places where panic is not an option
+pub(crate) fn try_boot_services() -> Option<NonNull<r_efi::efi::BootServices>> {
+    let system_table: NonNull<r_efi::efi::SystemTable> = uefi::env::try_system_table()?.cast();
+    let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
+    NonNull::new(boot_services)
+}
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/mod.rs b/library/std/src/sys/uefi/mod.rs
new file mode 100644
index 00000000000..193d4ecc16f
--- /dev/null
+++ b/library/std/src/sys/uefi/mod.rs
@@ -0,0 +1,155 @@
+//! 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
+
+#![deny(unsafe_op_in_unsafe_fn)]
+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;
+#[path = "../unsupported/os.rs"]
+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/time.rs"]
+pub mod time;
+
+pub(crate) mod common;
+
+#[cfg(test)]
+mod tests;
+
+use crate::io as std_io;
+use crate::os::uefi;
+use crate::ptr::NonNull;
+
+pub mod memchr {
+    pub use core::slice::memchr::{memchr, memrchr};
+}
+
+// SAFETY: must be called only once during runtime initialization.
+// SAFETY: argc must be 2.
+// SAFETY: argv must be &[Handle, *mut SystemTable].
+pub 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 { crate::os::uefi::env::init_globals(image_handle, system_table) };
+}
+
+// SAFETY: must be called only once during runtime cleanup.
+// NOTE: this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {}
+
+#[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: i32) -> crate::io::ErrorKind {
+    use crate::io::ErrorKind;
+    use r_efi::efi::Status;
+
+    if let Ok(code) = usize::try_from(code) {
+        common::status_to_io_error(Status::from_usize(code)).kind()
+    } else {
+        ErrorKind::Uncategorized
+    }
+}
+
+pub fn abort_internal() -> ! {
+    if let (Some(boot_services), Some(handle)) =
+        (common::try_boot_services(), uefi::env::try_image_handle())
+    {
+        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 = common::locate_handles(rng::PROTOCOL_GUID).ok()?;
+    for handle in handles {
+        if let Ok(protocol) = common::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
+}
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..d65d68337d8 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -44,6 +44,8 @@ cfg_if::cfg_if! {
 
 cfg_if::cfg_if! {
     if #[cfg(any(target_os = "l4re",
+                 target_os = "hermit",
+                 target_os = "uefi",
                  feature = "restricted-std",
                  all(target_family = "wasm", not(target_os = "emscripten")),
                  target_os = "xous",
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 176ef8e92db..836328f94ef 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -532,11 +532,7 @@ pub struct Target {
 impl Target {
     pub fn from_triple(triple: &str) -> Self {
         let mut target: Self = Default::default();
-        if triple.contains("-none")
-            || triple.contains("nvptx")
-            || triple.contains("switch")
-            || triple.contains("-uefi")
-        {
+        if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
             target.no_std = true;
         }
         target
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index 03fa284620e..8d4d60e12fb 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -19,8 +19,8 @@ Available targets:
 ## Requirements
 
 All UEFI targets can be used as `no-std` environments via cross-compilation.
-Support for `std` is missing, but actively worked on. `alloc` is supported if
-an allocator is provided by the user. No host tools are supported.
+Support for `std` is present, but incomplete and extreamly new. `alloc` is supported if
+an allocator is provided by the user or if using std. No host tools are supported.
 
 The UEFI environment resembles the environment for Microsoft Windows, with some
 minor differences. Therefore, cross-compiling for UEFI works with the same
@@ -230,3 +230,71 @@ pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Statu
     efi::Status::SUCCESS
 }
 ```
+
+## Rust std for UEFI
+This section contains information on how to use std on UEFI.
+
+### Build std
+The building std part is pretty much the same as the official [docs](https://rustc-dev-guide.rust-lang.org/getting-started.html).
+The linker that should be used is `rust-lld`. Here is a sample `config.toml`:
+```toml
+[llvm]
+download-ci-llvm = false
+[rust]
+lld = true
+[target.x86_64-unknown-uefi]
+linker = "rust-lld"
+```
+Then just build using `x.py`:
+```sh
+./x.py build --target x86_64-unknown-uefi
+```
+
+### Std Requirements
+The current std has a few basic requirements to function:
+1. Memory Allocation Services (`EFI_BOOT_SERVICES.AllocatePool()` and
+   `EFI_BOOT_SERVICES.FreePool()`) are available.
+If the above requirement is satisfied, the Rust code will reach `main`.
+Now we will discuss what the different modules of std use in UEFI.
+
+### Implemented features
+#### alloc
+- Implemented using `EFI_BOOT_SERVICES.AllocatePool()` and `EFI_BOOT_SERVICES.FreePool()`.
+- Passes all the tests.
+- Some Quirks:
+  - Currently uses `EfiLoaderData` as the `EFI_ALLOCATE_POOL->PoolType`.
+#### cmath
+- Provided by compiler-builtins.
+#### env
+- Just some global consants.
+#### locks
+- Uses `unsupported/locks`.
+- They should work for a platform without threads according to docs.
+#### os_str
+- Uses WTF-8 from windows.
+
+## Example: Hello World With std
+The following code is a valid UEFI application showing stdio in UEFI. It also
+uses `alloc` type `OsString` and `Vec`.
+
+This example can be compiled as binary crate via `cargo` using the toolchain
+compiled from the above source (named custom):
+
+```sh
+cargo +custom build --target x86_64-unknown-uefi
+```
+
+```rust,ignore (platform-specific)
+use r_efi::efi;
+use std::os::uefi::ffi::OsStrExt;
+use std::{ffi::OsString, panic};
+
+pub fn main() {
+  let st = std::os::uefi::env::system_table().as_ptr() as *mut efi::SystemTable;
+  let mut s: Vec<u16> = OsString::from("Hello World!\n").encode_wide().collect();
+  s.push(0);
+  let r =
+      unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) };
+  assert!(!r.is_error())
+}
+```
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 843ffe2c4c3..daa9cb8d22e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -18,6 +18,7 @@ const LICENSES: &[&str] = &[
     "Apache-2.0/MIT",
     "ISC",
     "MIT / Apache-2.0",
+    "MIT OR Apache-2.0 OR LGPL-2.1-or-later",              // r-efi, r-efi-alloc
     "MIT OR Apache-2.0 OR Zlib",                           // tinyvec_macros
     "MIT OR Apache-2.0",
     "MIT OR Zlib OR Apache-2.0",                           // miniz_oxide
@@ -217,6 +218,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "pulldown-cmark",
     "punycode",
     "quote",
+    "r-efi",
+    "r-efi-alloc",
     "rand",
     "rand_chacha",
     "rand_core",