1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 13 * distribution. 14 * 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 26 * SUCH DAMAGE. 27 */ 28 29 /* ChangeLog for this library: 30 * 31 * NDK r7c: Fix CPU count computation. The old method only reported the 32 * number of _active_ CPUs when the library was initialized, 33 * which could be less than the real total. 34 * 35 * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7 36 * for an ARMv6 CPU (see below). 37 * 38 * Handle kernels that only report 'neon', and not 'vfpv3' 39 * (VFPv3 is mandated by the ARM architecture is Neon is implemented) 40 * 41 * Handle kernels that only report 'vfpv3d16', and not 'vfpv3' 42 * 43 * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in 44 * android_getCpuFamily(). 45 * 46 * NDK r4: Initial release 47 */ 48 #include <sys/system_properties.h> 49 #ifdef __arm__ 50 #include <machine/cpu-features.h> 51 #endif 52 #include <pthread.h> 53 #include "cpu-features.h" 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <fcntl.h> 57 #include <errno.h> 58 59 static pthread_once_t g_once; 60 static AndroidCpuFamily g_cpuFamily; 61 static uint64_t g_cpuFeatures; 62 static int g_cpuCount; 63 64 static const int android_cpufeatures_debug = 0; 65 66 #ifdef __arm__ 67 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM 68 #elif defined __i386__ 69 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86 70 #else 71 # define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN 72 #endif 73 74 #define D(...) \ 75 do { \ 76 if (android_cpufeatures_debug) { \ 77 printf(__VA_ARGS__); fflush(stdout); \ 78 } \ 79 } while (0) 80 81 #ifdef __i386__ 82 static __inline__ void x86_cpuid(int func, int values[4]) 83 { 84 int a, b, c, d; 85 /* We need to preserve ebx since we're compiling PIC code */ 86 /* this means we can't use "=b" for the second output register */ 87 __asm__ __volatile__ ( \ 88 "push %%ebx\n" 89 "cpuid\n" \ 90 "mov %1, %%ebx\n" 91 "pop %%ebx\n" 92 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ 93 : "a" (func) \ 94 ); 95 values[0] = a; 96 values[1] = b; 97 values[2] = c; 98 values[3] = d; 99 } 100 #endif 101 102 /* Read the content of /proc/cpuinfo into a user-provided buffer. 103 * Return the length of the data, or -1 on error. Does *not* 104 * zero-terminate the content. Will not read more 105 * than 'buffsize' bytes. 106 */ 107 static int 108 read_file(const char* pathname, char* buffer, size_t buffsize) 109 { 110 int fd, len; 111 112 fd = open(pathname, O_RDONLY); 113 if (fd < 0) 114 return -1; 115 116 do { 117 len = read(fd, buffer, buffsize); 118 } while (len < 0 && errno == EINTR); 119 120 close(fd); 121 122 return len; 123 } 124 125 /* Extract the content of a the first occurence of a given field in 126 * the content of /proc/cpuinfo and return it as a heap-allocated 127 * string that must be freed by the caller. 128 * 129 * Return NULL if not found 130 */ 131 static char* 132 extract_cpuinfo_field(char* buffer, int buflen, const char* field) 133 { 134 int fieldlen = strlen(field); 135 char* bufend = buffer + buflen; 136 char* result = NULL; 137 int len, ignore; 138 const char *p, *q; 139 140 /* Look for first field occurence, and ensures it starts the line. 141 */ 142 p = buffer; 143 bufend = buffer + buflen; 144 for (;;) { 145 p = memmem(p, bufend-p, field, fieldlen); 146 if (p == NULL) 147 goto EXIT; 148 149 if (p == buffer || p[-1] == '\n') 150 break; 151 152 p += fieldlen; 153 } 154 155 /* Skip to the first column followed by a space */ 156 p += fieldlen; 157 p = memchr(p, ':', bufend-p); 158 if (p == NULL || p[1] != ' ') 159 goto EXIT; 160 161 /* Find the end of the line */ 162 p += 2; 163 q = memchr(p, '\n', bufend-p); 164 if (q == NULL) 165 q = bufend; 166 167 /* Copy the line into a heap-allocated buffer */ 168 len = q-p; 169 result = malloc(len+1); 170 if (result == NULL) 171 goto EXIT; 172 173 memcpy(result, p, len); 174 result[len] = '\0'; 175 176 EXIT: 177 return result; 178 } 179 180 /* Like strlen(), but for constant string literals */ 181 #define STRLEN_CONST(x) ((sizeof(x)-1) 182 183 184 /* Checks that a space-separated list of items contains one given 'item'. 185 * Returns 1 if found, 0 otherwise. 186 */ 187 static int 188 has_list_item(const char* list, const char* item) 189 { 190 const char* p = list; 191 int itemlen = strlen(item); 192 193 if (list == NULL) 194 return 0; 195 196 while (*p) { 197 const char* q; 198 199 /* skip spaces */ 200 while (*p == ' ' || *p == '\t') 201 p++; 202 203 /* find end of current list item */ 204 q = p; 205 while (*q && *q != ' ' && *q != '\t') 206 q++; 207 208 if (itemlen == q-p && !memcmp(p, item, itemlen)) 209 return 1; 210 211 /* skip to next item */ 212 p = q; 213 } 214 return 0; 215 } 216 217 /* Parse an decimal integer starting from 'input', but not going further 218 * than 'limit'. Return the value into '*result'. 219 * 220 * NOTE: Does not skip over leading spaces, or deal with sign characters. 221 * NOTE: Ignores overflows. 222 * 223 * The function returns NULL in case of error (bad format), or the new 224 * position after the decimal number in case of success (which will always 225 * be <= 'limit'). 226 */ 227 static const char* 228 parse_decimal(const char* input, const char* limit, int* result) 229 { 230 const char* p = input; 231 int val = 0; 232 while (p < limit) { 233 int d = (*p - '0'); 234 if ((unsigned)d >= 10U) 235 break; 236 val = val*10 + d; 237 p++; 238 } 239 if (p == input) 240 return NULL; 241 242 *result = val; 243 return p; 244 } 245 246 /* This small data type is used to represent a CPU list / mask, as read 247 * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology.txt 248 * 249 * For now, we don't expect more than 32 cores on mobile devices, so keep 250 * everything simple. 251 */ 252 typedef struct { 253 uint32_t mask; 254 } CpuList; 255 256 static __inline__ void 257 cpulist_init(CpuList* list) { 258 list->mask = 0; 259 } 260 261 static __inline__ void 262 cpulist_and(CpuList* list1, CpuList* list2) { 263 list1->mask &= list2->mask; 264 } 265 266 static __inline__ void 267 cpulist_set(CpuList* list, int index) { 268 if ((unsigned)index < 32) { 269 list->mask |= (uint32_t)(1U << index); 270 } 271 } 272 273 static __inline__ int 274 cpulist_count(CpuList* list) { 275 return __builtin_popcount(list->mask); 276 } 277 278 /* Parse a textual list of cpus and store the result inside a CpuList object. 279 * Input format is the following: 280 * - comma-separated list of items (no spaces) 281 * - each item is either a single decimal number (cpu index), or a range made 282 * of two numbers separated by a single dash (-). Ranges are inclusive. 283 * 284 * Examples: 0 285 * 2,4-127,128-143 286 * 0-1 287 */ 288 static void 289 cpulist_parse(CpuList* list, const char* line, int line_len) 290 { 291 const char* p = line; 292 const char* end = p + line_len; 293 const char* q; 294 295 /* NOTE: the input line coming from sysfs typically contains a 296 * trailing newline, so take care of it in the code below 297 */ 298 while (p < end && *p != '\n') 299 { 300 int val, start_value, end_value; 301 302 /* Find the end of current item, and put it into 'q' */ 303 q = memchr(p, ',', end-p); 304 if (q == NULL) { 305 q = end; 306 } 307 308 /* Get first value */ 309 p = parse_decimal(p, q, &start_value); 310 if (p == NULL) 311 goto BAD_FORMAT; 312 313 end_value = start_value; 314 315 /* If we're not at the end of the item, expect a dash and 316 * and integer; extract end value. 317 */ 318 if (p < q && *p == '-') { 319 p = parse_decimal(p+1, q, &end_value); 320 if (p == NULL) 321 goto BAD_FORMAT; 322 } 323 324 /* Set bits CPU list bits */ 325 for (val = start_value; val <= end_value; val++) { 326 cpulist_set(list, val); 327 } 328 329 /* Jump to next item */ 330 p = q; 331 if (p < end) 332 p++; 333 } 334 335 BAD_FORMAT: 336 ; 337 } 338 339 /* Read a CPU list from one sysfs file */ 340 static void 341 cpulist_read_from(CpuList* list, const char* filename) 342 { 343 char file[64]; 344 int filelen; 345 346 cpulist_init(list); 347 348 filelen = read_file(filename, file, sizeof file); 349 if (filelen < 0) { 350 D("Could not read %s: %s\n", filename, strerror(errno)); 351 return; 352 } 353 354 cpulist_parse(list, file, filelen); 355 } 356 357 /* Return the number of cpus present on a given device. 358 * 359 * To handle all weird kernel configurations, we need to compute the 360 * intersection of the 'present' and 'possible' CPU lists and count 361 * the result. 362 */ 363 static int 364 get_cpu_count(void) 365 { 366 CpuList cpus_present[1]; 367 CpuList cpus_possible[1]; 368 369 cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present"); 370 cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible"); 371 372 /* Compute the intersection of both sets to get the actual number of 373 * CPU cores that can be used on this device by the kernel. 374 */ 375 cpulist_and(cpus_present, cpus_possible); 376 377 return cpulist_count(cpus_present); 378 } 379 380 static void 381 android_cpuInit(void) 382 { 383 char cpuinfo[4096]; 384 int cpuinfo_len; 385 386 g_cpuFamily = DEFAULT_CPU_FAMILY; 387 g_cpuFeatures = 0; 388 g_cpuCount = 1; 389 390 cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo); 391 D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, 392 cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); 393 394 if (cpuinfo_len < 0) /* should not happen */ { 395 return; 396 } 397 398 /* Count the CPU cores, the value may be 0 for single-core CPUs */ 399 g_cpuCount = get_cpu_count(); 400 if (g_cpuCount == 0) { 401 g_cpuCount = 1; 402 } 403 404 D("found cpuCount = %d\n", g_cpuCount); 405 406 #ifdef __ARM_ARCH__ 407 { 408 char* features = NULL; 409 char* architecture = NULL; 410 411 /* Extract architecture from the "CPU Architecture" field. 412 * The list is well-known, unlike the the output of 413 * the 'Processor' field which can vary greatly. 414 * 415 * See the definition of the 'proc_arch' array in 416 * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in 417 * same file. 418 */ 419 char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); 420 421 if (cpuArch != NULL) { 422 char* end; 423 long archNumber; 424 int hasARMv7 = 0; 425 426 D("found cpuArch = '%s'\n", cpuArch); 427 428 /* read the initial decimal number, ignore the rest */ 429 archNumber = strtol(cpuArch, &end, 10); 430 431 /* Here we assume that ARMv8 will be upwards compatible with v7 432 * in the future. Unfortunately, there is no 'Features' field to 433 * indicate that Thumb-2 is supported. 434 */ 435 if (end > cpuArch && archNumber >= 7) { 436 hasARMv7 = 1; 437 } 438 439 /* Unfortunately, it seems that certain ARMv6-based CPUs 440 * report an incorrect architecture number of 7! 441 * 442 * See http://code.google.com/p/android/issues/detail?id=10812 443 * 444 * We try to correct this by looking at the 'elf_format' 445 * field reported by the 'Processor' field, which is of the 446 * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for 447 * an ARMv6-one. 448 */ 449 if (hasARMv7) { 450 char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, 451 "Processor"); 452 if (cpuProc != NULL) { 453 D("found cpuProc = '%s'\n", cpuProc); 454 if (has_list_item(cpuProc, "(v6l)")) { 455 D("CPU processor and architecture mismatch!!\n"); 456 hasARMv7 = 0; 457 } 458 free(cpuProc); 459 } 460 } 461 462 if (hasARMv7) { 463 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; 464 } 465 466 /* The LDREX / STREX instructions are available from ARMv6 */ 467 if (archNumber >= 6) { 468 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; 469 } 470 471 free(cpuArch); 472 } 473 474 /* Extract the list of CPU features from 'Features' field */ 475 char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features"); 476 477 if (cpuFeatures != NULL) { 478 479 D("found cpuFeatures = '%s'\n", cpuFeatures); 480 481 if (has_list_item(cpuFeatures, "vfpv3")) 482 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; 483 484 else if (has_list_item(cpuFeatures, "vfpv3d16")) 485 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; 486 487 if (has_list_item(cpuFeatures, "neon")) { 488 /* Note: Certain kernels only report neon but not vfpv3 489 * in their features list. However, ARM mandates 490 * that if Neon is implemented, so must be VFPv3 491 * so always set the flag. 492 */ 493 g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON | 494 ANDROID_CPU_ARM_FEATURE_VFPv3; 495 } 496 free(cpuFeatures); 497 } 498 } 499 #endif /* __ARM_ARCH__ */ 500 501 #ifdef __i386__ 502 g_cpuFamily = ANDROID_CPU_FAMILY_X86; 503 504 int regs[4]; 505 506 /* According to http://en.wikipedia.org/wiki/CPUID */ 507 #define VENDOR_INTEL_b 0x756e6547 508 #define VENDOR_INTEL_c 0x6c65746e 509 #define VENDOR_INTEL_d 0x49656e69 510 511 x86_cpuid(0, regs); 512 int vendorIsIntel = (regs[1] == VENDOR_INTEL_b && 513 regs[2] == VENDOR_INTEL_c && 514 regs[3] == VENDOR_INTEL_d); 515 516 x86_cpuid(1, regs); 517 if ((regs[2] & (1 << 9)) != 0) { 518 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; 519 } 520 if ((regs[2] & (1 << 23)) != 0) { 521 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; 522 } 523 if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) { 524 g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; 525 } 526 #endif 527 528 #ifdef _MIPS_ARCH 529 g_cpuFamily = ANDROID_CPU_FAMILY_MIPS; 530 #endif /* _MIPS_ARCH */ 531 } 532 533 534 AndroidCpuFamily 535 android_getCpuFamily(void) 536 { 537 pthread_once(&g_once, android_cpuInit); 538 return g_cpuFamily; 539 } 540 541 542 uint64_t 543 android_getCpuFeatures(void) 544 { 545 pthread_once(&g_once, android_cpuInit); 546 return g_cpuFeatures; 547 } 548 549 550 int 551 android_getCpuCount(void) 552 { 553 pthread_once(&g_once, android_cpuInit); 554 return g_cpuCount; 555 } 556