diff options
author | 2022-06-29 23:08:44 -0700 | |
---|---|---|
committer | 2022-06-29 23:08:44 -0700 | |
commit | 78a3dc768eae00d08821fd2410782d8af358b7b8 (patch) | |
tree | f195612bf55476ea36a545d2f8b3eaed89c00a10 | |
parent | f6c19b56c79c2f9c273d5cc4fd0358f058d6ac61 (diff) | |
download | rust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.tar.gz rust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.tar.zst rust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.zip |
Fixes #124.
-rw-r--r-- | CHANGELOG.md | 9 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/lib.rs | 7 | ||||
-rw-r--r-- | src/time.rs | 62 |
4 files changed, 64 insertions, 17 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 310a85d..0b4d0a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.50.0] - 2022-07-29 + +- `rdtscp` now returns a tuple in the form of `(cycles: u64, aux: u32)`, where + `cycles` is the cycle count (as returned by this function in previous + versions) and `aux` is the value of `IA32_TSC_AUX` -- which also gets read-out + by `rdtscp`. If one prefers to use the old signature, the recommendation is to + replace calls for `x86::time::rdtscp` with `core::arch::x86_64::__rdtscp`. + Fixes #124. + ## [0.49.0] - 2022-06-03 - Removed `x86::its64::segmentation::fs_deref()`: Users should replace calls to @@ -1,6 +1,6 @@ [package] name = "x86" -version = "0.49.0" +version = "0.50.0" authors = [ "Gerd Zellweger <mail@gerdzellweger.com>", "Eric Kidd <git@randomhacks.net>", @@ -67,4 +67,3 @@ optional = true klogger = { version = "0.0.11", features = ["use_ioports"] } x86test = { path = "x86test" } libc = "0.2.*" - @@ -108,8 +108,11 @@ mod x86testing { /// Read Processor ID /// -/// Reads the value of the IA32_TSC_AUX MSR (address C0000103H) -/// into the destination register. +/// Reads the value of the IA32_TSC_AUX MSR (address C0000103H) into the +/// destination register. +/// +/// # See also +/// `IA32_TSC_AUX` can also be read calling [`crate::time::rdtscp`]. /// /// # Safety /// May fail with #UD if rdpid is not supported (check CPUID). diff --git a/src/time.rs b/src/time.rs index d70322b..bae8e2b 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,6 +1,7 @@ //! Functions to read time stamp counters on x86. +use core::arch::asm; -use crate::arch::{__rdtscp, _rdtsc}; +use crate::arch::_rdtsc; /// Read the time stamp counter. /// @@ -21,20 +22,41 @@ pub unsafe fn rdtsc() -> u64 { /// Read the time stamp counter. /// -/// The RDTSCP instruction waits until all previous instructions -/// have been executed before reading the counter. -/// However, subsequent instructions may begin execution -/// before the read operation is performed. +/// The RDTSCP instruction waits until all previous instructions have been +/// executed before reading the counter. However, subsequent instructions may +/// begin execution before the read operation is performed. /// -/// Volatile is used here because the function may be used to act as -/// an instruction barrier. +/// Volatile is used here because the function may be used to act as an +/// instruction barrier. +/// +/// # Returns +/// - The current time stamp counter value of the CPU as a `u64`. +/// - The contents of `IA32_TSC_AUX` on that particular core. This is an OS +/// defined value. For example, Linux writes `numa_id << 12 | core_id` into +/// it. See also [`crate::rdpid`]. +/// +/// # Note +/// One can use `core::arch::x86_64::__rdtscp` from the Rust core library as +/// well. We don't rely on it because it only returns the time-stamp counter of +/// rdtscp and not the contents of `IA32_TSC_AUX`. /// /// # Safety -/// * Causes a GP fault if the TSD flag in register CR4 is set and the -/// CPL is greater than 0. -pub unsafe fn rdtscp() -> u64 { - let mut _aux = 0; - __rdtscp(&mut _aux) +/// * Causes a GP fault if the TSD flag in register CR4 is set and the CPL is +/// greater than 0. +pub unsafe fn rdtscp() -> (u64, u32) { + let eax: u32; + let ecx: u32; + let edx: u32; + asm!( + "rdtscp", + lateout("eax") eax, + lateout("ecx") ecx, + lateout("edx") edx, + options(nomem, nostack) + ); + + let counter: u64 = (edx as u64) << 32 | eax as u64; + (counter, ecx) } #[cfg(all(test, feature = "utest"))] @@ -64,7 +86,21 @@ mod test { if has_rdtscp { unsafe { - assert!(rdtscp() > 0, "rdtscp returned 0, unlikely!"); + // Check cycle counter: + assert!(rdtscp().0 > 0, "rdtscp returned 0, unlikely!"); + + // Check TSC AUX is correct (currently when using Linux only): + // See also: https://elixir.bootlin.com/linux/v5.18.8/source/arch/x86/include/asm/segment.h#L241 + if cfg!(target_os = "linux") { + let mut cpu: u32 = 0; + let mut node: u32 = 0; + libc::syscall(libc::SYS_getcpu, &mut cpu, &mut node, 0); + assert_eq!( + rdtscp().1, + node << 12 | cpu, + "rdtscp AUX didn't match getcpu call!" + ); + } } } } |