safe_intrinsics/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Provides a safe wrapper around some CPU instructions.
5//!
6//! This is needed because Rust's intrinsics are marked unsafe (despite
7//! these few being completely safe to invoke).
8
9#![no_std]
10// UNSAFETY: Calling a cpu intrinsic.
11#![expect(unsafe_code)]
12
13/// Invokes the cpuid instruction with input values `eax` and `ecx`.
14#[cfg(target_arch = "x86_64")]
15pub fn cpuid(eax: u32, ecx: u32) -> core::arch::x86_64::CpuidResult {
16    // SAFETY: this instruction is always safe to invoke. If the instruction is
17    // for some reason not supported, the process will fault in an OS-specific
18    // way, but this will not cause memory safety violations.
19    unsafe { core::arch::x86_64::__cpuid_count(eax, ecx) }
20}
21
22/// Invokes the rdtsc instruction.
23#[cfg(target_arch = "x86_64")]
24pub fn rdtsc() -> u64 {
25    // SAFETY: The tsc is safe to read.
26    unsafe { core::arch::x86_64::_rdtsc() }
27}
28
29/// Emit a store fence to flush the processor's store buffer
30pub fn store_fence() {
31    #[cfg(target_arch = "x86_64")]
32    {
33        // SAFETY: this instruction has no safety requirements.
34        unsafe { core::arch::x86_64::_mm_sfence() }
35    }
36    #[cfg(target_arch = "aarch64")]
37    {
38        // SAFETY: this instruction has no safety requirements.
39        unsafe { core::arch::asm!("dsb st", options(nostack)) };
40    }
41    #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
42    {
43        compile_error!("Unsupported architecture");
44    }
45
46    // Make the compiler aware.
47    core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release);
48}