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}