Skip to main content

aleo_std_cpu/
lib.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16/// Uses Rust's `cpuid` function from the `arch` module.
17pub(crate) mod native_cpuid {
18    /// Low-level data-structure to store result of cpuid instruction.
19    #[derive(Copy, Clone, Eq, PartialEq)]
20    #[repr(C)]
21    pub struct CpuIdResult {
22        /// Return value EAX register
23        pub eax: u32,
24        /// Return value EBX register
25        pub ebx: u32,
26        /// Return value ECX register
27        pub ecx: u32,
28        /// Return value EDX register
29        pub edx: u32,
30    }
31
32    #[allow(unreachable_code)]
33    #[allow(unused_variables)]
34    pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult {
35        #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(target_env = "sgx")))]
36        {
37            #[cfg(all(target_arch = "x86", target_feature = "sse"))]
38            use core::arch::x86 as arch;
39            #[cfg(target_arch = "x86_64")]
40            use core::arch::x86_64 as arch;
41
42            // Safety: CPUID is supported on all x86_64 CPUs and all x86 CPUs with SSE, but not by SGX.
43            let result = unsafe { arch::__cpuid_count(a, c) };
44            return CpuIdResult {
45                eax: result.eax,
46                ebx: result.ebx,
47                ecx: result.ecx,
48                edx: result.edx,
49            };
50        }
51
52        CpuIdResult {
53            eax: 22,
54            ebx: 1970169159,
55            ecx: 1818588270,
56            edx: 1231384169,
57        }
58    }
59}
60
61///
62/// Vendor Info String (LEAF=0x0)
63///
64/// The vendor info is a 12-byte (96 bit) long string stored in `ebx`, `edx` and
65/// `ecx` by the corresponding `cpuid` instruction.
66///
67#[derive(PartialEq, Eq)]
68#[repr(C)]
69struct VendorInfo {
70    ebx: u32,
71    edx: u32,
72    ecx: u32,
73}
74
75impl VendorInfo {
76    /// Return vendor identification as string, such as "AuthenticAMD" or "GenuineIntel".
77    fn as_str(&self) -> &str {
78        let brand_string_start = self as *const VendorInfo as *const u8;
79        let slice = unsafe {
80            // Safety: VendorInfo is laid out with repr(C) and exactly
81            // 12 byte long without any padding.
82            core::slice::from_raw_parts(brand_string_start, core::mem::size_of::<VendorInfo>())
83        };
84        core::str::from_utf8(slice).unwrap_or("InvalidVendorString")
85    }
86}
87
88#[derive(Copy, Clone, Debug, PartialEq, Eq)]
89pub enum Cpu {
90    AMD,
91    Intel,
92    Unknown,
93}
94
95///
96/// Returns a new Cpu enum.
97///
98/// The vendor leaf will contain a ASCII readable string such as "GenuineIntel"
99/// for Intel CPUs or "AuthenticAMD" for AMD CPUs.
100///
101#[allow(clippy::absurd_extreme_comparisons)]
102pub fn get_cpu() -> Cpu {
103    const EAX_VENDOR_INFO: u32 = 0x0;
104
105    // Check if a non extended leaf  (`val`) is supported.
106    let vendor_leaf = native_cpuid::cpuid_count(EAX_VENDOR_INFO, 0);
107    let is_leaf_supported = EAX_VENDOR_INFO <= vendor_leaf.eax;
108
109    match is_leaf_supported {
110        true => {
111            let vendor = VendorInfo {
112                ebx: vendor_leaf.ebx,
113                ecx: vendor_leaf.ecx,
114                edx: vendor_leaf.edx,
115            };
116
117            match vendor.as_str() {
118                "AuthenticAMD" => Cpu::AMD,
119                "GenuineIntel" => Cpu::Intel,
120                _ => Cpu::Unknown,
121            }
122        }
123        false => Cpu::Unknown,
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_get_cpu() {
133        println!("{:?}", get_cpu());
134    }
135}