lib.rs
1 // Copyright (C) 2019-2021 Alpha-Delta Network Inc. 2 // This file is part of the alphastd library. 3 4 // The alphastd 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 alphastd 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 alphastd library. If not, see <https://www.gnu.org/licenses/>. 16 17 /// Uses Rust's `cpuid` function from the `arch` module. 18 pub(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)] 70 struct VendorInfo { 71 ebx: u32, 72 edx: u32, 73 ecx: u32, 74 } 75 76 impl 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)] 90 pub 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)] 103 pub 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)] 129 mod tests { 130 use super::*; 131 132 #[test] 133 fn test_get_cpu() { 134 println!("{:?}", get_cpu()); 135 } 136 }