Botan 2.19.3
Crypto and TLS for C&
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 macOS and OpenBSD ppc, use sysctl to detect AltiVec
15*/
16#if defined(BOTAN_TARGET_OS_IS_MACOS)
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#endif
23
24#endif
25
26namespace Botan {
27
28#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY)
29
30/*
31* PowerPC specific block: check for AltiVec using either
32* sysctl or by reading processor version number register.
33*/
34uint64_t CPUID::CPUID_Data::detect_cpu_features(size_t* cache_line_size)
35 {
36 BOTAN_UNUSED(cache_line_size);
37
38#if defined(BOTAN_TARGET_OS_IS_MACOS) || defined(BOTAN_TARGET_OS_IS_OPENBSD)
39 // On macOS and OpenBSD, use sysctl
40
41 int sels[2] = {
42#if defined(BOTAN_TARGET_OS_IS_OPENBSD)
43 CTL_MACHDEP, CPU_ALTIVEC
44#else
45 CTL_HW, HW_VECTORUNIT
46#endif
47 };
48
49 int vector_type = 0;
50 size_t length = sizeof(vector_type);
51 int error = ::sysctl(sels, 2, &vector_type, &length, NULL, 0);
52
53 if(error == 0 && vector_type > 0)
54 return CPUID::CPUID_ALTIVEC_BIT;
55
56#elif (defined(BOTAN_TARGET_OS_HAS_GETAUXVAL) || defined(BOTAN_TARGET_HAS_ELF_AUX_INFO)) && defined(BOTAN_TARGET_ARCH_IS_PPC64)
57
58 enum PPC_hwcap_bit {
59 ALTIVEC_bit = (1 << 28),
60 CRYPTO_bit = (1 << 25),
61 DARN_bit = (1 << 21),
62
63 ARCH_hwcap_altivec = 16, // AT_HWCAP
64 ARCH_hwcap_crypto = 26, // AT_HWCAP2
65 };
66
67 uint64_t detected_features = 0;
68
69 const unsigned long hwcap_altivec = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_altivec);
70 if(hwcap_altivec & PPC_hwcap_bit::ALTIVEC_bit)
71 detected_features |= CPUID::CPUID_ALTIVEC_BIT;
72
73 const unsigned long hwcap_crypto = OS::get_auxval(PPC_hwcap_bit::ARCH_hwcap_crypto);
74 if(hwcap_crypto & PPC_hwcap_bit::CRYPTO_bit)
75 detected_features |= CPUID::CPUID_POWER_CRYPTO_BIT;
76 if(hwcap_crypto & PPC_hwcap_bit::DARN_bit)
77 detected_features |= CPUID::CPUID_DARN_BIT;
78
79 return detected_features;
80
81#else
82
83 /*
84 On PowerPC, MSR 287 is PVR, the Processor Version Number
85 Normally it is only accessible to ring 0, but Linux and NetBSD
86 (others, too, maybe?) will trap and emulate it for us.
87 */
88
89 int pvr = OS::run_cpu_instruction_probe([]() noexcept -> int {
90 uint32_t pvr = 0;
91 asm volatile("mfspr %0, 287" : "=r" (pvr));
92 // Top 16 bits suffice to identify the model
93 return static_cast<int>(pvr >> 16);
94 });
95
96 if(pvr > 0)
97 {
98 const uint16_t ALTIVEC_PVR[] = {
99 0x003E, // IBM POWER6
100 0x003F, // IBM POWER7
101 0x004A, // IBM POWER7p
102 0x004B, // IBM POWER8E
103 0x004C, // IBM POWER8 NVL
104 0x004D, // IBM POWER8
105 0x004E, // IBM POWER9
106 0x000C, // G4-7400
107 0x0039, // G5 970
108 0x003C, // G5 970FX
109 0x0044, // G5 970MP
110 0x0070, // Cell PPU
111 0, // end
112 };
113
114 for(size_t i = 0; ALTIVEC_PVR[i]; ++i)
115 {
116 if(pvr == ALTIVEC_PVR[i])
117 return CPUID::CPUID_ALTIVEC_BIT;
118 }
119
120 return 0;
121 }
122
123 // TODO try direct instruction probing
124
125#endif
126
127 return 0;
128 }
129
130#endif
131
132}
#define BOTAN_UNUSED(...)
Definition assert.h:142
unsigned long get_auxval(unsigned long id)
Definition os_utils.cpp:109
int BOTAN_TEST_API run_cpu_instruction_probe(std::function< int()> probe_fn)
Definition os_utils.cpp:616