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