about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/lib.rs4
-rw-r--r--library/std/src/sys/pal/common/thread_local/fast_local.rs3
-rw-r--r--library/std/src/sys/pal/uefi/time.rs116
-rw-r--r--library/std/src/sys/pal/unix/thread.rs30
-rw-r--r--library/std/src/sys/pal/windows/c/README.md9
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt (renamed from library/std/src/sys/pal/windows/c/windows_sys.lst)3
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs7
7 files changed, 157 insertions, 15 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index cab3e399ffa..c6cd2c6786a 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -263,6 +263,10 @@
 #![cfg_attr(any(windows, target_os = "uefi"), feature(round_char_boundary))]
 #![cfg_attr(target_os = "xous", feature(slice_ptr_len))]
 #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))]
+#![cfg_attr(
+    all(any(target_arch = "x86_64", target_arch = "x86"), target_os = "uefi"),
+    feature(stdarch_x86_has_cpuid)
+)]
 //
 // Language features:
 // tidy-alphabetical-start
diff --git a/library/std/src/sys/pal/common/thread_local/fast_local.rs b/library/std/src/sys/pal/common/thread_local/fast_local.rs
index 0fdca27852c..04c0dd6f750 100644
--- a/library/std/src/sys/pal/common/thread_local/fast_local.rs
+++ b/library/std/src/sys/pal/common/thread_local/fast_local.rs
@@ -94,7 +94,8 @@ pub macro thread_local_inner {
                         if let $crate::option::Option::Some(init) = init {
                             if let $crate::option::Option::Some(value) = init.take() {
                                 return value;
-                            } else if $crate::cfg!(debug_assertions) {
+                            }
+                            if $crate::cfg!(debug_assertions) {
                                 $crate::unreachable!("missing default value");
                             }
                         }
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index 68f428c38fb..76562cf9f51 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -14,6 +14,15 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
 impl Instant {
     pub fn now() -> Instant {
+        // If we have a timestamp protocol, use it.
+        if let Some(x) = instant_internal::timestamp_protocol() {
+            return x;
+        }
+
+        if let Some(x) = instant_internal::platform_specific() {
+            return x;
+        }
+
         panic!("time not implemented on this platform")
     }
 
@@ -103,3 +112,110 @@ pub(crate) mod system_time_internal {
         Duration::new(utc_epoch, t.nanosecond)
     }
 }
+
+pub(crate) mod instant_internal {
+    use super::super::helpers;
+    use super::*;
+    use crate::mem::MaybeUninit;
+    use crate::ptr::NonNull;
+    use crate::sync::atomic::{AtomicPtr, Ordering};
+    use crate::sys_common::mul_div_u64;
+    use r_efi::protocols::timestamp;
+
+    const NS_PER_SEC: u64 = 1_000_000_000;
+
+    pub fn timestamp_protocol() -> Option<Instant> {
+        fn try_handle(handle: NonNull<crate::ffi::c_void>) -> Option<u64> {
+            let protocol: NonNull<timestamp::Protocol> =
+                helpers::open_protocol(handle, timestamp::PROTOCOL_GUID).ok()?;
+            let mut properties: MaybeUninit<timestamp::Properties> = MaybeUninit::uninit();
+
+            let r = unsafe { ((*protocol.as_ptr()).get_properties)(properties.as_mut_ptr()) };
+            if r.is_error() {
+                return None;
+            }
+
+            let freq = unsafe { properties.assume_init().frequency };
+            let ts = unsafe { ((*protocol.as_ptr()).get_timestamp)() };
+            Some(mul_div_u64(ts, NS_PER_SEC, freq))
+        }
+
+        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+            AtomicPtr::new(crate::ptr::null_mut());
+
+        if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
+            if let Some(ns) = try_handle(handle) {
+                return Some(Instant(Duration::from_nanos(ns)));
+            }
+        }
+
+        if let Ok(handles) = helpers::locate_handles(timestamp::PROTOCOL_GUID) {
+            for handle in handles {
+                if let Some(ns) = try_handle(handle) {
+                    LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
+                    return Some(Instant(Duration::from_nanos(ns)));
+                }
+            }
+        }
+
+        None
+    }
+
+    pub fn platform_specific() -> Option<Instant> {
+        cfg_if::cfg_if! {
+            if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
+                timestamp_rdtsc().map(Instant)
+            } else {
+                None
+            }
+        }
+    }
+
+    #[cfg(target_arch = "x86_64")]
+    fn timestamp_rdtsc() -> Option<Duration> {
+        if !crate::arch::x86_64::has_cpuid() {
+            return None;
+        }
+
+        static FREQUENCY: crate::sync::OnceLock<u64> = crate::sync::OnceLock::new();
+
+        // Get Frequency in Mhz
+        // Inspired by [`edk2/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c`](https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c)
+        let freq = FREQUENCY
+            .get_or_try_init(|| {
+                let cpuid = unsafe { crate::arch::x86_64::__cpuid(0x15) };
+                if cpuid.eax == 0 || cpuid.ebx == 0 || cpuid.ecx == 0 {
+                    return Err(());
+                }
+                Ok(mul_div_u64(cpuid.ecx as u64, cpuid.ebx as u64, cpuid.eax as u64))
+            })
+            .ok()?;
+
+        let ts = unsafe { crate::arch::x86_64::_rdtsc() };
+        let ns = mul_div_u64(ts, 1000, *freq);
+        Some(Duration::from_nanos(ns))
+    }
+
+    #[cfg(target_arch = "x86")]
+    fn timestamp_rdtsc() -> Option<Duration> {
+        if !crate::arch::x86::has_cpuid() {
+            return None;
+        }
+
+        static FREQUENCY: crate::sync::OnceLock<u64> = crate::sync::OnceLock::new();
+
+        let freq = FREQUENCY
+            .get_or_try_init(|| {
+                let cpuid = unsafe { crate::arch::x86::__cpuid(0x15) };
+                if cpuid.eax == 0 || cpuid.ebx == 0 || cpuid.ecx == 0 {
+                    return Err(());
+                }
+                Ok(mul_div_u64(cpuid.ecx as u64, cpuid.ebx as u64, cpuid.eax as u64))
+            })
+            .ok()?;
+
+        let ts = unsafe { crate::arch::x86::_rdtsc() };
+        let ns = mul_div_u64(ts, 1000, *freq);
+        Some(Duration::from_nanos(ns))
+    }
+}
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 767f269dbea..97976407bb4 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -847,11 +847,31 @@ pub mod guard {
             let stackptr = get_stack_start_aligned()?;
             let guardaddr = stackptr.addr();
             // Technically the number of guard pages is tunable and controlled
-            // by the security.bsd.stack_guard_page sysctl, but there are
-            // few reasons to change it from the default. The default value has
-            // been 1 ever since FreeBSD 11.1 and 10.4.
-            const GUARD_PAGES: usize = 1;
-            let guard = guardaddr..guardaddr + GUARD_PAGES * page_size;
+            // by the security.bsd.stack_guard_page sysctl.
+            // By default it is 1, checking once is enough since it is
+            // a boot time config value.
+            static LOCK: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
+            let guard = guardaddr
+                ..guardaddr
+                    + *LOCK.get_or_init(|| {
+                        use crate::sys::weak::dlsym;
+                        dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
+                        let mut guard: usize = 0;
+                        let mut size = crate::mem::size_of_val(&guard);
+                        let oid = crate::ffi::CStr::from_bytes_with_nul(
+                            b"security.bsd.stack_guard_page\0",
+                        )
+                        .unwrap();
+                        match sysctlbyname.get() {
+                            Some(fcn) => {
+                                if fcn(oid.as_ptr(), &mut guard as *mut _ as *mut _, &mut size as *mut _ as *mut _, crate::ptr::null_mut(), 0) == 0 {
+                                    return guard;
+                                }
+                                return 1;
+                            },
+                            _ => { return 1; }
+                        }
+                    }) * page_size;
             Some(guard)
         } else if cfg!(target_os = "openbsd") {
             // OpenBSD stack already includes a guard page, and stack is
diff --git a/library/std/src/sys/pal/windows/c/README.md b/library/std/src/sys/pal/windows/c/README.md
new file mode 100644
index 00000000000..d458e55efbc
--- /dev/null
+++ b/library/std/src/sys/pal/windows/c/README.md
@@ -0,0 +1,9 @@
+The `windows_sys.rs` file is autogenerated from `bindings.txt` and must not
+be edited manually.
+
+To add bindings, edit `bindings.txt` then regenerate using the following command:
+
+    ./x run generate-windows-sys && ./x fmt library/std
+
+If you need to override generated functions or types then add them to
+`library/std/src/sys/pal/windows/c.rs`.
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.lst b/library/std/src/sys/pal/windows/c/bindings.txt
index f91e1054a04..726f1c3df82 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.lst
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -1,7 +1,6 @@
 --out windows_sys.rs
 --config flatten std
 --filter
-// tidy-alphabetical-start
 !Windows.Win32.Foundation.INVALID_HANDLE_VALUE
 Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
 Windows.Wdk.Storage.FileSystem.FILE_CONTAINS_EXTENDED_CREATE_INFORMATION
@@ -2592,5 +2591,3 @@ Windows.Win32.System.Threading.WakeAllConditionVariable
 Windows.Win32.System.Threading.WakeConditionVariable
 Windows.Win32.System.WindowsProgramming.PROGRESS_CONTINUE
 Windows.Win32.UI.Shell.GetUserProfileDirectoryW
-// tidy-alphabetical-end
-
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index b38b70c8983..c386b66a722 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,9 +1,3 @@
-// This file is autogenerated.
-//
-// To add bindings, edit windows_sys.lst then use `./x run generate-windows-sys` to
-// regenerate the bindings.
-//
-// ignore-tidy-filelength
 // Bindings generated by `windows-bindgen` 0.52.0
 
 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
@@ -4351,3 +4345,4 @@ impl ::core::clone::Clone for XSAVE_FORMAT {
         *self
     }
 }
+// ignore-tidy-filelength