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}