lib.rs
1 // Copyright (c) 2025 ADnet Contributors 2 // This file is part of the alpha-std 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. 17 pub(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( 36 any(target_arch = "x86", target_arch = "x86_64"), 37 not(target_env = "sgx") 38 ))] 39 { 40 #[cfg(all(target_arch = "x86", target_feature = "sse"))] 41 use core::arch::x86 as arch; 42 #[cfg(target_arch = "x86_64")] 43 use core::arch::x86_64 as arch; 44 45 // Safety: CPUID is supported on all x86_64 CPUs and all x86 CPUs with SSE, but not by SGX. 46 let result = unsafe { arch::__cpuid_count(a, c) }; 47 return CpuIdResult { 48 eax: result.eax, 49 ebx: result.ebx, 50 ecx: result.ecx, 51 edx: result.edx, 52 }; 53 } 54 55 CpuIdResult { 56 eax: 22, 57 ebx: 1970169159, 58 ecx: 1818588270, 59 edx: 1231384169, 60 } 61 } 62 } 63 64 /// 65 /// Vendor Info String (LEAF=0x0) 66 /// 67 /// The vendor info is a 12-byte (96 bit) long string stored in `ebx`, `edx` and 68 /// `ecx` by the corresponding `cpuid` instruction. 69 /// 70 #[derive(PartialEq, Eq)] 71 #[repr(C)] 72 struct VendorInfo { 73 ebx: u32, 74 edx: u32, 75 ecx: u32, 76 } 77 78 impl VendorInfo { 79 /// Return vendor identification as string, such as "AuthenticAMD" or "GenuineIntel". 80 fn as_str(&self) -> &str { 81 let brand_string_start = self as *const VendorInfo as *const u8; 82 let slice = unsafe { 83 // Safety: VendorInfo is laid out with repr(C) and exactly 84 // 12 byte long without any padding. 85 core::slice::from_raw_parts(brand_string_start, core::mem::size_of::<VendorInfo>()) 86 }; 87 core::str::from_utf8(slice).unwrap_or("InvalidVendorString") 88 } 89 } 90 91 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 92 pub enum Cpu { 93 AMD, 94 Intel, 95 Unknown, 96 } 97 98 /// 99 /// Returns a new Cpu enum. 100 /// 101 /// The vendor leaf will contain a ASCII readable string such as "GenuineIntel" 102 /// for Intel CPUs or "AuthenticAMD" for AMD CPUs. 103 /// 104 #[allow(clippy::absurd_extreme_comparisons)] 105 pub fn get_cpu() -> Cpu { 106 const EAX_VENDOR_INFO: u32 = 0x0; 107 108 // Check if a non extended leaf (`val`) is supported. 109 let vendor_leaf = native_cpuid::cpuid_count(EAX_VENDOR_INFO, 0); 110 let is_leaf_supported = EAX_VENDOR_INFO <= vendor_leaf.eax; 111 112 match is_leaf_supported { 113 true => { 114 let vendor = VendorInfo { 115 ebx: vendor_leaf.ebx, 116 ecx: vendor_leaf.ecx, 117 edx: vendor_leaf.edx, 118 }; 119 120 match vendor.as_str() { 121 "AuthenticAMD" => Cpu::AMD, 122 "GenuineIntel" => Cpu::Intel, 123 _ => Cpu::Unknown, 124 } 125 } 126 false => Cpu::Unknown, 127 } 128 } 129 130 #[cfg(test)] 131 mod tests { 132 use super::*; 133 134 #[test] 135 fn test_get_cpu() { 136 println!("{:?}", get_cpu()); 137 } 138 }