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