/ cpu / src / lib.rs
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  }