about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs13
-rw-r--r--library/panic_abort/src/lib.rs2
-rw-r--r--library/std/build.rs1
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/mod.rs1
-rw-r--r--library/std/src/os/uefi/env.rs54
-rw-r--r--library/std/src/sys/uefi/helpers.rs14
-rw-r--r--library/std/src/sys/uefi/mod.rs36
-rw-r--r--library/std/src/sys/uefi/os.rs42
-rw-r--r--src/doc/rustc/src/platform-support/unknown-uefi.md10
10 files changed, 111 insertions, 63 deletions
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4753f125540..6c51dffedbf 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -421,7 +421,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         entry_type: EntryFnType,
     ) -> Bx::Function {
         // 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.
+        // `usize efi_main(void *handle, void *system_table)` 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 {
@@ -508,10 +508,9 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         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);
+        let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 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)]);
+        let arg_argv_el1 = bx.gep(cx.type_ptr(), 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 {
@@ -566,11 +565,7 @@ 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/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs
index bc0d7287be5..6e097e2caf2 100644
--- a/library/panic_abort/src/lib.rs
+++ b/library/panic_abort/src/lib.rs
@@ -44,7 +44,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 = "xous",
                             target_os = "uefi",
         ))] {
             unsafe fn abort() -> ! {
diff --git a/library/std/build.rs b/library/std/build.rs
index 1c32b425650..36516978b7a 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -52,7 +52,6 @@ fn main() {
         // - mipsel-sony-psp
         // - nvptx64-nvidia-cuda
         // - arch=avr
-        // - 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 b572347019c..5e3249655b8 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -263,6 +263,7 @@
 #![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 d1a73503899..41aa0472f52 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -142,7 +142,6 @@ pub mod solid;
 #[cfg(target_os = "tvos")]
 #[path = "ios/mod.rs"]
 pub(crate) mod tvos;
-#[cfg(target_os = "uefi")]
 #[cfg(any(target_os = "uefi", doc))]
 pub mod uefi;
 #[cfg(target_os = "vita")]
diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs
index 4dd090e22c6..5d082e7c113 100644
--- a/library/std/src/os/uefi/env.rs
+++ b/library/std/src/os/uefi/env.rs
@@ -2,23 +2,22 @@
 
 #![unstable(feature = "uefi_std", issue = "100499")]
 
-use crate::{cell::Cell, ffi::c_void, ptr::NonNull};
+use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::{ffi::c_void, ptr::NonNull};
 
-// Since UEFI is single-threaded, making the global variables thread local should be safe.
-thread_local! {
-    // Flag to check if BootServices are still valid.
-    // Start with assuming that they are not available
-    static BOOT_SERVICES_FLAG: Cell<bool> = Cell::new(false);
-    // Position 0 = SystemTable
-    // Position 1 = ImageHandle
-    static GLOBALS: Cell<Option<(NonNull<c_void>, NonNull<c_void>)>> = Cell::new(None);
-}
+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.
 ///
@@ -26,9 +25,26 @@ thread_local! {
 /// 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.
-pub unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
-    GLOBALS.set(Some((system_table, handle)));
+/// # 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.
@@ -50,7 +66,7 @@ pub fn image_handle() -> NonNull<c_void> {
 /// 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.get() {
+    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())
@@ -62,19 +78,15 @@ pub fn boot_services() -> Option<NonNull<c_void>> {
 /// 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>> {
-    GLOBALS.get().map(|x| x.0)
+    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>> {
-    GLOBALS.get().map(|x| x.1)
-}
-
-pub(crate) fn enable_boot_services() {
-    BOOT_SERVICES_FLAG.set(true);
+    NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
 }
 
 pub(crate) fn disable_boot_services() {
-    BOOT_SERVICES_FLAG.set(false);
+    BOOT_SERVICES_FLAG.store(false, Ordering::Release)
 }
diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs
index 2e1bcb36944..126661bfc96 100644
--- a/library/std/src/sys/uefi/helpers.rs
+++ b/library/std/src/sys/uefi/helpers.rs
@@ -60,13 +60,14 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ff
     }
 
     // The returned buf_len is in bytes
-    let mut buf: Vec<r_efi::efi::Handle> =
-        Vec::with_capacity(buf_len / size_of::<r_efi::efi::Handle>());
+    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(buf_len / size_of::<r_efi::efi::Handle>()) };
+            unsafe { buf.set_len(num_of_handles) };
             Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect())
         }
         Err(e) => Err(e),
@@ -114,16 +115,15 @@ pub(crate) fn create_event(
 ) -> io::Result<NonNull<crate::ffi::c_void>> {
     let boot_services: NonNull<efi::BootServices> =
         boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
-    let mut exit_boot_service_event: r_efi::efi::Event = crate::ptr::null_mut();
+    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 exit_boot_service_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(exit_boot_service_event)
-            .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+        NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
     }
 }
 
diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs
index 85d00caf149..9a10395af8e 100644
--- a/library/std/src/sys/uefi/mod.rs
+++ b/library/std/src/sys/uefi/mod.rs
@@ -12,7 +12,6 @@
 //! [`OsStr`]: crate::ffi::OsStr
 //! [`OsString`]: crate::ffi::OsString
 
-#![deny(unsafe_op_in_unsafe_fn)]
 pub mod alloc;
 #[path = "../unsupported/args.rs"]
 pub mod args;
@@ -43,6 +42,8 @@ pub mod stdio;
 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;
 
@@ -53,18 +54,17 @@ mod tests;
 
 pub type RawOsError = usize;
 
-use crate::cell::Cell;
 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};
 }
 
-thread_local! {
-    static EXIT_BOOT_SERVICE_EVENT: Cell<Option<NonNull<crate::ffi::c_void>>> = Cell::new(None);
-}
+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.
@@ -75,8 +75,6 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
     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) };
-    // Enable boot services once GLOBALS are initialized
-    uefi::env::enable_boot_services();
 
     // Register exit boot services handler
     match helpers::create_event(
@@ -86,7 +84,17 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
         crate::ptr::null_mut(),
     ) {
         Ok(x) => {
-            EXIT_BOOT_SERVICE_EVENT.set(Some(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(),
     }
@@ -96,7 +104,9 @@ pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
 /// 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) = EXIT_BOOT_SERVICE_EVENT.take() {
+    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) };
     }
 }
@@ -159,7 +169,9 @@ pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind {
 }
 
 pub fn abort_internal() -> ! {
-    if let Some(exit_boot_service_event) = EXIT_BOOT_SERVICE_EVENT.take() {
+    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) };
     }
 
@@ -226,3 +238,7 @@ fn get_random() -> Option<(u64, u64)> {
 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
index cd489d8f7f9..e6693db68e6 100644
--- a/library/std/src/sys/uefi/os.rs
+++ b/library/std/src/sys/uefi/os.rs
@@ -4,15 +4,16 @@ 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 {
-    use r_efi::efi::Status;
-
     // 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) {
@@ -160,12 +161,7 @@ impl fmt::Display for JoinPathsError {
     }
 }
 
-impl StdError for JoinPathsError {
-    #[allow(deprecated)]
-    fn description(&self) -> &str {
-        "not supported on this platform yet"
-    }
-}
+impl StdError for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
     unsupported()
@@ -173,6 +169,14 @@ pub fn current_exe() -> io::Result<PathBuf> {
 
 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)> {
@@ -180,6 +184,13 @@ impl Iterator for Env {
     }
 }
 
+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")
 }
@@ -204,7 +215,20 @@ pub fn home_dir() -> Option<PathBuf> {
     None
 }
 
-pub fn exit(_code: i32) -> ! {
+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()
 }
 
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index 019f030eb1c..68cd7fae319 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -277,7 +277,9 @@ cargo +custom build --target x86_64-unknown-uefi
 ```
 
 ```rust,ignore (platform-specific)
-use r_efi::efi;
+#![feature(uefi_std)]
+
+use r_efi::{efi, protocols::simple_text_output};
 use std::{
   ffi::OsString,
   os::uefi::{env, ffi::OsStrExt}
@@ -290,7 +292,7 @@ pub fn main() {
   let r =
       unsafe {
         let con_out: *mut simple_text_output::Protocol = (*st).con_out;
-        let output_string: extern "efiapi" fn(_: *mut simple_text_output::Protocol, *mut u16) = (*con_out).output_string;
+        let output_string: extern "efiapi" fn(_: *mut simple_text_output::Protocol, *mut u16) -> efi::Status = (*con_out).output_string;
         output_string(con_out, s.as_ptr() as *mut efi::Char16)
       };
   assert!(!r.is_error())
@@ -298,6 +300,6 @@ pub fn main() {
 ```
 
 ### BootServices
-The current implementation of std make `BootServices` unavailable once `ExitBootServices` is called. Refer to [Runtime Drivers](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/7_driver_entry_point/711_runtime_drivers) for more information regarding how to handle switching from using physical addresses to using virtual addresses.
+The current implementation of std makes `BootServices` unavailable once `ExitBootServices` is called. Refer to [Runtime Drivers](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/7_driver_entry_point/711_runtime_drivers) for more information regarding how to handle switching from using physical addresses to using virtual addresses.
 
-Note: It should be noted that it is upto the user to drop all allocated memory before `ExitBootServices` is called.
+Note: It should be noted that it is up to the user to drop all allocated memory before `ExitBootServices` is called.