2 * Copyright (C) 2010 The Android Open Source Project
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 /* ChangeLog for this library:
31 * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7
32 * for an ARMv6 CPU (see below).
34 * Handle kernels that only report 'neon', and not 'vfpv3'
35 * (VFPv3 is mandated by the ARM architecture is Neon is implemented)
37 * Handle kernels that only report 'vfpv3d16', and not 'vfpv3'
39 * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in
40 * android_getCpuFamily().
42 * NDK r4: Initial release
44 #include <sys/system_properties.h>
46 #include <machine/cpu-features.h>
49 #include "cpu-features.h"
55 static pthread_once_t g_once
;
56 static AndroidCpuFamily g_cpuFamily
;
57 static uint64_t g_cpuFeatures
;
58 static int g_cpuCount
;
60 static const int android_cpufeatures_debug
= 0;
63 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
64 #elif defined __i386__
65 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
67 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
72 if (android_cpufeatures_debug) { \
73 printf(__VA_ARGS__); fflush(stdout); \
77 /* Read the content of /proc/cpuinfo into a user-provided buffer.
78 * Return the length of the data, or -1 on error. Does *not*
79 * zero-terminate the content. Will not read more
80 * than 'buffsize' bytes.
83 read_file(const char* pathname
, char* buffer
, size_t buffsize
)
87 fd
= open(pathname
, O_RDONLY
);
92 len
= read(fd
, buffer
, buffsize
);
93 } while (len
< 0 && errno
== EINTR
);
100 /* Extract the content of a the first occurence of a given field in
101 * the content of /proc/cpuinfo and return it as a heap-allocated
102 * string that must be freed by the caller.
104 * Return NULL if not found
107 extract_cpuinfo_field(char* buffer
, int buflen
, const char* field
)
109 int fieldlen
= strlen(field
);
110 char* bufend
= buffer
+ buflen
;
115 /* Look for first field occurence, and ensures it starts the line.
118 bufend
= buffer
+ buflen
;
120 p
= memmem(p
, bufend
-p
, field
, fieldlen
);
124 if (p
== buffer
|| p
[-1] == '\n')
130 /* Skip to the first column followed by a space */
132 p
= memchr(p
, ':', bufend
-p
);
133 if (p
== NULL
|| p
[1] != ' ')
136 /* Find the end of the line */
138 q
= memchr(p
, '\n', bufend
-p
);
142 /* Copy the line into a heap-allocated buffer */
144 result
= malloc(len
+1);
148 memcpy(result
, p
, len
);
155 /* Count the number of occurences of a given field prefix in /proc/cpuinfo.
158 count_cpuinfo_field(char* buffer
, int buflen
, const char* field
)
160 int fieldlen
= strlen(field
);
161 const char* p
= buffer
;
162 const char* bufend
= buffer
+ buflen
;
169 p
= memmem(p
, bufend
-p
, field
, fieldlen
);
173 /* Ensure that the field is at the start of a line */
174 if (p
> buffer
&& p
[-1] != '\n') {
180 /* skip any whitespace */
182 while (q
< bufend
&& (*q
== ' ' || *q
== '\t'))
185 /* we must have a colon now */
186 if (q
< bufend
&& *q
== ':') {
196 /* Like strlen(), but for constant string literals */
197 #define STRLEN_CONST(x) ((sizeof(x)-1)
200 /* Checks that a space-separated list of items contains one given 'item'.
201 * Returns 1 if found, 0 otherwise.
204 has_list_item(const char* list
, const char* item
)
206 const char* p
= list
;
207 int itemlen
= strlen(item
);
216 while (*p
== ' ' || *p
== '\t')
219 /* find end of current list item */
221 while (*q
&& *q
!= ' ' && *q
!= '\t')
224 if (itemlen
== q
-p
&& !memcmp(p
, item
, itemlen
))
227 /* skip to next item */
235 android_cpuInit(void)
240 g_cpuFamily
= DEFAULT_CPU_FAMILY
;
244 cpuinfo_len
= read_file("/proc/cpuinfo", cpuinfo
, sizeof cpuinfo
);
245 D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len
,
246 cpuinfo_len
>= 0 ? cpuinfo_len
: 0, cpuinfo
);
248 if (cpuinfo_len
< 0) /* should not happen */ {
252 /* Count the CPU cores, the value may be 0 for single-core CPUs */
253 g_cpuCount
= count_cpuinfo_field(cpuinfo
, cpuinfo_len
, "processor");
254 if (g_cpuCount
== 0) {
255 g_cpuCount
= count_cpuinfo_field(cpuinfo
, cpuinfo_len
, "Processor");
256 if (g_cpuCount
== 0) {
261 D("found cpuCount = %d\n", g_cpuCount
);
265 char* features
= NULL
;
266 char* architecture
= NULL
;
268 /* Extract architecture from the "CPU Architecture" field.
269 * The list is well-known, unlike the the output of
270 * the 'Processor' field which can vary greatly.
272 * See the definition of the 'proc_arch' array in
273 * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
276 char* cpuArch
= extract_cpuinfo_field(cpuinfo
, cpuinfo_len
, "CPU architecture");
278 if (cpuArch
!= NULL
) {
283 D("found cpuArch = '%s'\n", cpuArch
);
285 /* read the initial decimal number, ignore the rest */
286 archNumber
= strtol(cpuArch
, &end
, 10);
288 /* Here we assume that ARMv8 will be upwards compatible with v7
289 * in the future. Unfortunately, there is no 'Features' field to
290 * indicate that Thumb-2 is supported.
292 if (end
> cpuArch
&& archNumber
>= 7) {
296 /* Unfortunately, it seems that certain ARMv6-based CPUs
297 * report an incorrect architecture number of 7!
299 * See http://code.google.com/p/android/issues/detail?id=10812
301 * We try to correct this by looking at the 'elf_format'
302 * field reported by the 'Processor' field, which is of the
303 * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
307 char* cpuProc
= extract_cpuinfo_field(cpuinfo
, cpuinfo_len
,
309 if (cpuProc
!= NULL
) {
310 D("found cpuProc = '%s'\n", cpuProc
);
311 if (has_list_item(cpuProc
, "(v6l)")) {
312 D("CPU processor and architecture mismatch!!\n");
320 g_cpuFeatures
|= ANDROID_CPU_ARM_FEATURE_ARMv7
;
323 /* The LDREX / STREX instructions are available from ARMv6 */
324 if (archNumber
>= 6) {
325 g_cpuFeatures
|= ANDROID_CPU_ARM_FEATURE_LDREX_STREX
;
331 /* Extract the list of CPU features from 'Features' field */
332 char* cpuFeatures
= extract_cpuinfo_field(cpuinfo
, cpuinfo_len
, "Features");
334 if (cpuFeatures
!= NULL
) {
336 D("found cpuFeatures = '%s'\n", cpuFeatures
);
338 if (has_list_item(cpuFeatures
, "vfpv3"))
339 g_cpuFeatures
|= ANDROID_CPU_ARM_FEATURE_VFPv3
;
341 else if (has_list_item(cpuFeatures
, "vfpv3d16"))
342 g_cpuFeatures
|= ANDROID_CPU_ARM_FEATURE_VFPv3
;
344 if (has_list_item(cpuFeatures
, "neon")) {
345 /* Note: Certain kernels only report neon but not vfpv3
346 * in their features list. However, ARM mandates
347 * that if Neon is implemented, so must be VFPv3
348 * so always set the flag.
350 g_cpuFeatures
|= ANDROID_CPU_ARM_FEATURE_NEON
|
351 ANDROID_CPU_ARM_FEATURE_VFPv3
;
356 #endif /* __ARM_ARCH__ */
359 g_cpuFamily
= ANDROID_CPU_FAMILY_X86
;
365 android_getCpuFamily(void)
367 pthread_once(&g_once
, android_cpuInit
);
373 android_getCpuFeatures(void)
375 pthread_once(&g_once
, android_cpuInit
);
376 return g_cpuFeatures
;
381 android_getCpuCount(void)
383 pthread_once(&g_once
, android_cpuInit
);