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