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}