aleo_std_cpu/
lib.rs

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