aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Gerd Zellweger <mail@gerdzellweger.com> 2022-06-29 23:08:44 -0700
committerGravatar Gerd Zellweger <mail@gerdzellweger.com> 2022-06-29 23:08:44 -0700
commit78a3dc768eae00d08821fd2410782d8af358b7b8 (patch)
treef195612bf55476ea36a545d2f8b3eaed89c00a10
parentf6c19b56c79c2f9c273d5cc4fd0358f058d6ac61 (diff)
downloadrust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.tar.gz
rust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.tar.zst
rust-x86-78a3dc768eae00d08821fd2410782d8af358b7b8.zip
Fixes #124.
-rw-r--r--CHANGELOG.md9
-rw-r--r--Cargo.toml3
-rw-r--r--src/lib.rs7
-rw-r--r--src/time.rs62
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
diff --git a/Cargo.toml b/Cargo.toml
index f49ca40..8a4c581 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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.*"
-
diff --git a/src/lib.rs b/src/lib.rs
index b505446..0c35999 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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!"
+ );
+ }
}
}
}