summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/uefi/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/uefi/mod.rs')
-rw-r--r--library/std/src/sys/uefi/mod.rs244
1 files changed, 244 insertions, 0 deletions
diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs
new file mode 100644
index 000000000..9a10395af
--- /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
+}