Botan  2.7.0
Crypto and TLS for C++11
cpuid_ppc.cpp
Go to the documentation of this file.
1 /*
2 * Runtime CPU detection for POWER/PowerPC
3 * (C) 2009,2010,2013,2017 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/cpuid.h>
9 #include <botan/internal/os_utils.h>
10 
11 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
12 
13 /*
14 * On Darwin and OpenBSD ppc, use sysctl to detect AltiVec
15 */
16 #if defined(BOTAN_TARGET_OS_IS_DARWIN)
17  #include <sys/sysctl.h>
18 #elif defined(BOTAN_TARGET_OS_IS_OPENBSD)
19  #include <sys/param.h>
20  #include <sys/sysctl.h>
21  #include <machine/cpu.h>
22 #elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL)
23  #include <sys/auxv.h>
24 #endif
25 
26 #endif
27 
28 namespace Botan {
29 
30 #if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
31 
32 /*
33 * PowerPC specific block: check for AltiVec using either
34 * sysctl or by reading processor version number register.
35 */
36 uint64_t CPUID::detect_cpu_features(size_t* cache_line_size)
37  {
39 
40 #if defined(BOTAN_TARGET_OS_IS_DARWIN) || defined(BOTAN_TARGET_OS_IS_OPENBSD)
41  // On Darwin/OS X and OpenBSD, use sysctl
42 
43  int sels[2] = {
44 #if defined(BOTAN_TARGET_OS_IS_OPENBSD)
45  CTL_MACHDEP, CPU_ALTIVEC
46 #else
47  CTL_HW, HW_VECTORUNIT
48 #endif
49  };
50 
51  int vector_type = 0;
52  size_t length = sizeof(vector_type);
53  int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0);
54 
55  if(error == 0 && vector_type > 0)
56  return CPUID::CPUID_ALTIVEC_BIT;
57 
58 #elif defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) && defined(BOTAN_TARGET_ARCH_IS_PPC64)
59 
60  enum PPC_hwcap_bit {
61  ALTIVEC_bit = (1 << 28),
62  CRYPTO_bit = (1 << 25),
63 
64  ARCH_hwcap_altivec = 16, // AT_HWCAP
65  ARCH_hwcap_crypto = 26, // AT_HWCAP2
66  };
67 
68  uint64_t detected_features = 0;
69 
70  const unsigned long hwcap_altivec = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_altivec);
71  if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit)
72  detected_features |= CPUID::CPUID_ALTIVEC_BIT;
73 
74  const unsigned long hwcap_crypto = ::getauxval(PPC_hwcap_bit::ARCH_hwcap_crypto);
75  if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit)
76  detected_features |= CPUID::CPUID_PPC_CRYPTO_BIT;
77 
78  return detected_features;
79 
80 #else
81 
82  /*
83  On PowerPC, MSR 287 is PVR, the Processor Version Number
84  Normally it is only accessible to ring 0, but Linux and NetBSD
85  (others, too, maybe?) will trap and emulate it for us.
86  */
87 
88  int pvr = OS::run_cpu_instruction_probe([]() -> int {
89  uint32_t pvr = 0;
90  asm volatile("mfspr %0, 287" : "=r" (pvr));
91  // Top 16 bits suffice to identify the model
92  return static_cast<int>(pvr >> 16);
93  });
94 
95  if(pvr > 0)
96  {
97  const uint16_t ALTIVEC_PVR[] = {
98  0x003E, // IBM POWER6
99  0x003F, // IBM POWER7
100  0x004A, // IBM POWER7p
101  0x004D, // IBM POWER8
102  0x004B, // IBM POWER8E
103  0x000C, // G4-7400
104  0x0039, // G5 970
105  0x003C, // G5 970FX
106  0x0044, // G5 970MP
107  0x0070, // Cell PPU
108  0, // end
109  };
110 
111  for(size_t i = 0; ALTIVEC_PVR[i]; ++i)
112  {
113  if(pvr == ALTIVEC_PVR[i])
114  return CPUID::CPUID_ALTIVEC_BIT;
115  }
116 
117  return 0;
118  }
119 
120  // TODO try direct instruction probing
121 
122 #endif
123 
124  return 0;
125  }
126 
127 #endif
128 
129 }
int BOTAN_TEST_API run_cpu_instruction_probe(std::function< int()> probe_fn)
Definition: os_utils.cpp:395
static size_t cache_line_size()
Definition: cpuid.h:66
Definition: alg_id.cpp:13
#define BOTAN_UNUSED(...)
Definition: assert.h:130