blob: 715dc4f7d659116a08250b239719282893af688c [file] [log] [blame]
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +01001#include "cpu-features.h"
2#include "cpu_features_macros.h"
3#include "internal/filesystem.h"
4#include "internal/stack_line_reader.h"
5#include "internal/string_view.h"
6
7#include <pthread.h>
8
9#if defined(CPU_FEATURES_ARCH_ARM)
10#include "cpuinfo_arm.h"
11#elif defined(CPU_FEATURES_ARCH_X86)
12#include "cpuinfo_x86.h"
13#elif defined(CPU_FEATURES_ARCH_MIPS)
14#include "cpuinfo_mips.h"
15#elif defined(CPU_FEATURES_ARCH_AARCH64)
16#include "cpuinfo_aarch64.h"
17#endif
18
19static pthread_once_t g_once;
20static int g_inited;
21static uint64_t g_cpuFeatures;
22static int g_cpuCount;
23
24#ifdef CPU_FEATURES_ARCH_ARM
25static uint32_t g_cpuIdArm;
26#endif
27
28static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) {
29 *cpu_mask |= 1UL << index;
30}
31
32// Examples of valid inputs: "31", "4-31"
33static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) {
34 int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-');
35 if (separator_index < 0) { // A single cpu index
36 int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text);
37 if (cpu_index < 0) return;
38 set_cpu_mask_bit(cpu_index, cpu_mask);
39 } else {
40 int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber(
41 CpuFeatures_StringView_KeepFront(text, separator_index));
42 int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber(
43 CpuFeatures_StringView_PopFront(text, separator_index + 1));
44 int i;
45 if (cpu_index_a < 0 || cpu_index_b < 0) return;
46 for (i = cpu_index_a; i <= cpu_index_b; ++i) {
47 if (i < 32) {
48 set_cpu_mask_bit(i, cpu_mask);
49 }
50 }
51 }
52}
53
54// Format specification from
55// https://www.kernel.org/doc/Documentation/cputopology.txt
56// Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3"
57static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) {
58 if (!result.full_line || result.eof) return;
59 StringView line = result.line;
60 for (; line.size > 0;) {
61 int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ',');
62 if (next_entry_index < 0) {
63 parse_cpu_mask(line, cpu_mask);
64 break;
65 }
66 StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index);
67 parse_cpu_mask(entry, cpu_mask);
68 line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1);
69 }
70}
71
72static void update_cpu_mask_from_file(const char* filename,
73 uint32_t* cpu_mask) {
74 const int fd = CpuFeatures_OpenFile(filename);
75 if (fd >= 0) {
76 StackLineReader reader;
77 StackLineReader_Initialize(&reader, fd);
78 parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask);
79 CpuFeatures_CloseFile(fd);
80 }
81}
82
83static int get_cpu_count(void) {
84 uint32_t cpu_mask = 0;
85 update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask);
86 update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask);
87 return __builtin_popcount(cpu_mask);
88}
89
90static void android_cpuInit(void) {
91 g_cpuFeatures = 0;
92 g_cpuCount = 1;
93 g_inited = 1;
94
95 g_cpuCount = get_cpu_count();
96 if (g_cpuCount == 0) {
97 g_cpuCount = 1;
98 }
99#if defined(CPU_FEATURES_ARCH_ARM)
100 ArmInfo info = GetArmInfo();
101 if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
102 if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
Guillaume Chateleta528c7f2019-01-18 11:04:22 +0100103 if (info.features.neon) {
104 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
105 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32;
106 }
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100107 if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16;
108 if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
109 if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
110 if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
111 if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
112 if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
113 if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
114 if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
115 if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
Guillaume Chateleta528c7f2019-01-18 11:04:22 +0100116 if (info.architecture >= 6)
117 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
118 if (info.features.vfpv) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
119 if (info.features.vfpv4) {
120 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA;
121 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
122 }
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100123 g_cpuIdArm = GetArmCpuId(&info);
124#elif defined(CPU_FEATURES_ARCH_X86)
125 X86Info info = GetX86Info();
126 if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
Guillaume Chateletd395dfa2019-01-22 13:19:42 +0100127 if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
128 if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100129 if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
130 if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
Guillaume Chateletd395dfa2019-01-22 13:19:42 +0100131 if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100132 if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
Guillaume Chateletd395dfa2019-01-22 13:19:42 +0100133 if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100134 if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
Guillaume Chateletd395dfa2019-01-22 13:19:42 +0100135 if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100136#elif defined(CPU_FEATURES_ARCH_MIPS)
137 MipsInfo info = GetMipsInfo();
Guillaume Chatelet5911e962019-01-22 11:00:48 +0100138 if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
Guillaume Chateletdfdac6a2019-01-17 18:00:21 +0100139 if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
140#elif defined(CPU_FEATURES_ARCH_AARCH64)
141 Aarch64Info info = GetAarch64Info();
142 if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
143 if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
144 if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
145 if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
146 if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
147 if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
148 if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
149#endif
150}
151
152AndroidCpuFamily android_getCpuFamily(void) {
153#if defined(CPU_FEATURES_ARCH_ARM)
154 return ANDROID_CPU_FAMILY_ARM;
155#elif defined(CPU_FEATURES_ARCH_X86_32)
156 return ANDROID_CPU_FAMILY_X86;
157#elif defined(CPU_FEATURES_ARCH_MIPS64)
158 return ANDROID_CPU_FAMILY_MIPS64;
159#elif defined(CPU_FEATURES_ARCH_MIPS32)
160 return ANDROID_CPU_FAMILY_MIPS;
161#elif defined(CPU_FEATURES_ARCH_AARCH64)
162 return ANDROID_CPU_FAMILY_ARM64;
163#elif defined(CPU_FEATURES_ARCH_X86_64)
164 return ANDROID_CPU_FAMILY_X86_64;
165#else
166 return ANDROID_CPU_FAMILY_UNKNOWN;
167#endif
168}
169
170uint64_t android_getCpuFeatures(void) {
171 pthread_once(&g_once, android_cpuInit);
172 return g_cpuFeatures;
173}
174
175int android_getCpuCount(void) {
176 pthread_once(&g_once, android_cpuInit);
177 return g_cpuCount;
178}
179
180static void android_cpuInitDummy(void) { g_inited = 1; }
181
182int android_setCpu(int cpu_count, uint64_t cpu_features) {
183 /* Fail if the library was already initialized. */
184 if (g_inited) return 0;
185 g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
186 g_cpuFeatures = cpu_features;
187 pthread_once(&g_once, android_cpuInitDummy);
188 return 1;
189}
190
191#ifdef CPU_FEATURES_ARCH_ARM
192
193uint32_t android_getCpuIdArm(void) {
194 pthread_once(&g_once, android_cpuInit);
195 return g_cpuIdArm;
196}
197
198int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) {
199 if (!android_setCpu(cpu_count, cpu_features)) return 0;
200 g_cpuIdArm = cpu_id;
201 return 1;
202}
203
204#endif // CPU_FEATURES_ARCH_ARM