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