111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* 211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Copyright (C) 2010 The Android Open Source Project 311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * All rights reserved. 411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Redistribution and use in source and binary forms, with or without 611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * modification, are permitted provided that the following conditions 711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * are met: 811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * * Redistributions of source code must retain the above copyright 911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * notice, this list of conditions and the following disclaimer. 1011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * * Redistributions in binary form must reproduce the above copyright 1111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * notice, this list of conditions and the following disclaimer in 1211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the documentation and/or other materials provided with the 1311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * distribution. 1411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 1511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 1911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * SUCH DAMAGE. 2711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 2811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 2911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* ChangeLog for this library: 3011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 3111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r10e?: Add MIPS MSA feature. 3211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 3311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r10: Support for 64-bit CPUs (Intel, ARM & MIPS). 3411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 3511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r8d: Add android_setCpu(). 3611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 3711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r8c: Add new ARM CPU features: VFPv2, VFP_D32, VFP_FP16, 3811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFP_FMA, NEON_FMA, IDIV_ARM, IDIV_THUMB2 and iWMMXt. 3911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 4011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Rewrite the code to parse /proc/self/auxv instead of 4111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the "Features" field in /proc/cpuinfo. 4211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 4311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Dynamically allocate the buffer that hold the content 4411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * of /proc/cpuinfo to deal with newer hardware. 4511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 4611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r7c: Fix CPU count computation. The old method only reported the 4711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * number of _active_ CPUs when the library was initialized, 4811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * which could be less than the real total. 4911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 5011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7 5111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * for an ARMv6 CPU (see below). 5211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 5311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Handle kernels that only report 'neon', and not 'vfpv3' 5411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * (VFPv3 is mandated by the ARM architecture is Neon is implemented) 5511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 5611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Handle kernels that only report 'vfpv3d16', and not 'vfpv3' 5711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 5811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in 5911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * android_getCpuFamily(). 6011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 6111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NDK r4: Initial release 6211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 6311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 6411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "cpu-features.h" 6511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 6611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <dlfcn.h> 6711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <errno.h> 6811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <fcntl.h> 6911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <pthread.h> 7011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdio.h> 7111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <stdlib.h> 7211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <sys/system_properties.h> 7311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <unistd.h> 7411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 7511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic pthread_once_t g_once; 7611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int g_inited; 7711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic AndroidCpuFamily g_cpuFamily; 7811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint64_t g_cpuFeatures; 7911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int g_cpuCount; 8011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 8111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __arm__ 8211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t g_cpuIdArm; 8311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 8411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 8511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const int android_cpufeatures_debug = 0; 8611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 8711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define D(...) \ 8811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert do { \ 8911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (android_cpufeatures_debug) { \ 9011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert printf(__VA_ARGS__); fflush(stdout); \ 9111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } \ 9211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } while (0) 9311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 9411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __i386__ 9511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ void x86_cpuid(int func, int values[4]) 9611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 9711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int a, b, c, d; 9811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* We need to preserve ebx since we're compiling PIC code */ 9911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* this means we can't use "=b" for the second output register */ 10011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert __asm__ __volatile__ ( \ 10111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "push %%ebx\n" 10211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "cpuid\n" \ 10311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "mov %%ebx, %1\n" 10411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "pop %%ebx\n" 10511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ 10611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert : "a" (func) \ 10711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ); 10811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[0] = a; 10911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[1] = b; 11011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[2] = c; 11111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[3] = d; 11211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 11311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__x86_64__) 11411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ void x86_cpuid(int func, int values[4]) 11511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 11611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int64_t a, b, c, d; 11711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* We need to preserve ebx since we're compiling PIC code */ 11811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* this means we can't use "=b" for the second output register */ 11911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert __asm__ __volatile__ ( \ 12011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "push %%rbx\n" 12111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "cpuid\n" \ 12211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "mov %%rbx, %1\n" 12311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "pop %%rbx\n" 12411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ 12511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert : "a" (func) \ 12611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ); 12711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[0] = a; 12811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[1] = b; 12911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[2] = c; 13011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert values[3] = d; 13111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 13211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 13311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 13411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Get the size of a file by reading it until the end. This is needed 13511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * because files under /proc do not always return a valid size when 13611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed. 13711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 13811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int 13911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertget_file_size(const char* pathname) 14011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 14111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 14211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int fd, result = 0; 14311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char buffer[256]; 14411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 14511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert fd = open(pathname, O_RDONLY); 14611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (fd < 0) { 14711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Can't open %s: %s\n", pathname, strerror(errno)); 14811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return -1; 14911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 15011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 15111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (;;) { 15211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int ret = read(fd, buffer, sizeof buffer); 15311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret < 0) { 15411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (errno == EINTR) 15511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert continue; 15611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Error while reading %s: %s\n", pathname, strerror(errno)); 15711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 15811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 15911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret == 0) 16011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 16111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 16211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert result += ret; 16311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 16411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert close(fd); 16511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return result; 16611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 16711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 16811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Read the content of /proc/cpuinfo into a user-provided buffer. 16911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Return the length of the data, or -1 on error. Does *not* 17011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * zero-terminate the content. Will not read more 17111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * than 'buffsize' bytes. 17211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 17311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int 17411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertread_file(const char* pathname, char* buffer, size_t buffsize) 17511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 17611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int fd, count; 17711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 17811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert fd = open(pathname, O_RDONLY); 17911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (fd < 0) { 18011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Could not open %s: %s\n", pathname, strerror(errno)); 18111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return -1; 18211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 18311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert count = 0; 18411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (count < (int)buffsize) { 18511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int ret = read(fd, buffer + count, buffsize - count); 18611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret < 0) { 18711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (errno == EINTR) 18811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert continue; 18911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Error while reading from %s: %s\n", pathname, strerror(errno)); 19011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (count == 0) 19111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert count = -1; 19211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 19311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 19411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret == 0) 19511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 19611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert count += ret; 19711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 19811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert close(fd); 19911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return count; 20011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 20111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 20211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __arm__ 20311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Extract the content of a the first occurence of a given field in 20411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the content of /proc/cpuinfo and return it as a heap-allocated 20511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * string that must be freed by the caller. 20611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 20711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Return NULL if not found 20811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 20911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic char* 21011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertextract_cpuinfo_field(const char* buffer, int buflen, const char* field) 21111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 21211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int fieldlen = strlen(field); 21311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* bufend = buffer + buflen; 21411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* result = NULL; 21511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int len; 21611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char *p, *q; 21711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 21811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Look for first field occurence, and ensures it starts the line. */ 21911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = buffer; 22011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (;;) { 22111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = memmem(p, bufend-p, field, fieldlen); 22211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == NULL) 22311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert goto EXIT; 22411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 22511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == buffer || p[-1] == '\n') 22611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 22711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 22811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p += fieldlen; 22911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 23011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 23111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Skip to the first column followed by a space */ 23211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p += fieldlen; 23311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = memchr(p, ':', bufend-p); 23411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == NULL || p[1] != ' ') 23511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert goto EXIT; 23611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 23711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Find the end of the line */ 23811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p += 2; 23911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q = memchr(p, '\n', bufend-p); 24011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (q == NULL) 24111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q = bufend; 24211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 24311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Copy the line into a heap-allocated buffer */ 24411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert len = q-p; 24511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert result = malloc(len+1); 24611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (result == NULL) 24711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert goto EXIT; 24811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 24911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert memcpy(result, p, len); 25011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert result[len] = '\0'; 25111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 25211cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertEXIT: 25311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return result; 25411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 25511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 25611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Checks that a space-separated list of items contains one given 'item'. 25711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Returns 1 if found, 0 otherwise. 25811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 25911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int 26011cd02dfb91661c65134cac258cf5924270e9d2Dan Alberthas_list_item(const char* list, const char* item) 26111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 26211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* p = list; 26311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int itemlen = strlen(item); 26411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 26511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (list == NULL) 26611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 26711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 26811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (*p) { 26911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* q; 27011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 27111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* skip spaces */ 27211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (*p == ' ' || *p == '\t') 27311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p++; 27411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 27511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* find end of current list item */ 27611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q = p; 27711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (*q && *q != ' ' && *q != '\t') 27811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q++; 27911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 28011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (itemlen == q-p && !memcmp(p, item, itemlen)) 28111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 1; 28211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 28311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* skip to next item */ 28411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = q; 28511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 28611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 28711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 28811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __arm__ */ 28911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 29011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Parse a number starting from 'input', but not going further 29111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * than 'limit'. Return the value into '*result'. 29211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 29311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NOTE: Does not skip over leading spaces, or deal with sign characters. 29411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NOTE: Ignores overflows. 29511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 29611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * The function returns NULL in case of error (bad format), or the new 29711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * position after the decimal number in case of success (which will always 29811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * be <= 'limit'). 29911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 30011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const char* 30111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertparse_number(const char* input, const char* limit, int base, int* result) 30211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 30311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* p = input; 30411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int val = 0; 30511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (p < limit) { 30611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int d = (*p - '0'); 30711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((unsigned)d >= 10U) { 30811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert d = (*p - 'a'); 30911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((unsigned)d >= 6U) 31011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert d = (*p - 'A'); 31111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((unsigned)d >= 6U) 31211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 31311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert d += 10; 31411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 31511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (d >= base) 31611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 31711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert val = val*base + d; 31811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p++; 31911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 32011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == input) 32111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return NULL; 32211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 32311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert *result = val; 32411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return p; 32511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 32611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 32711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const char* 32811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertparse_decimal(const char* input, const char* limit, int* result) 32911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 33011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return parse_number(input, limit, 10, result); 33111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 33211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 33311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __arm__ 33411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic const char* 33511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertparse_hexadecimal(const char* input, const char* limit, int* result) 33611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 33711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return parse_number(input, limit, 16, result); 33811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 33911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __arm__ */ 34011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 34111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* This small data type is used to represent a CPU list / mask, as read 34211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology.txt 34311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 34411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * For now, we don't expect more than 32 cores on mobile devices, so keep 34511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * everything simple. 34611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 34711cd02dfb91661c65134cac258cf5924270e9d2Dan Alberttypedef struct { 34811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t mask; 34911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} CpuList; 35011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 35111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ void 35211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_init(CpuList* list) { 35311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert list->mask = 0; 35411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 35511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 35611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ void 35711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_and(CpuList* list1, CpuList* list2) { 35811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert list1->mask &= list2->mask; 35911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 36011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 36111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ void 36211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_set(CpuList* list, int index) { 36311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((unsigned)index < 32) { 36411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert list->mask |= (uint32_t)(1U << index); 36511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 36611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 36711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 36811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic __inline__ int 36911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_count(CpuList* list) { 37011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return __builtin_popcount(list->mask); 37111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 37211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 37311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Parse a textual list of cpus and store the result inside a CpuList object. 37411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Input format is the following: 37511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * - comma-separated list of items (no spaces) 37611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * - each item is either a single decimal number (cpu index), or a range made 37711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * of two numbers separated by a single dash (-). Ranges are inclusive. 37811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 37911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Examples: 0 38011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 2,4-127,128-143 38111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 0-1 38211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 38311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void 38411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_parse(CpuList* list, const char* line, int line_len) 38511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 38611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* p = line; 38711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* end = p + line_len; 38811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* q; 38911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 39011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* NOTE: the input line coming from sysfs typically contains a 39111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * trailing newline, so take care of it in the code below 39211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 39311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert while (p < end && *p != '\n') 39411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { 39511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int val, start_value, end_value; 39611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 39711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Find the end of current item, and put it into 'q' */ 39811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q = memchr(p, ',', end-p); 39911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (q == NULL) { 40011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert q = end; 40111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 40211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 40311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Get first value */ 40411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = parse_decimal(p, q, &start_value); 40511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == NULL) 40611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert goto BAD_FORMAT; 40711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 40811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert end_value = start_value; 40911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 41011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* If we're not at the end of the item, expect a dash and 41111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * and integer; extract end value. 41211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 41311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p < q && *p == '-') { 41411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = parse_decimal(p+1, q, &end_value); 41511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p == NULL) 41611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert goto BAD_FORMAT; 41711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 41811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 41911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Set bits CPU list bits */ 42011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (val = start_value; val <= end_value; val++) { 42111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_set(list, val); 42211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 42311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 42411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Jump to next item */ 42511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = q; 42611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p < end) 42711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p++; 42811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 42911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 43011cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertBAD_FORMAT: 43111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ; 43211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 43311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 43411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Read a CPU list from one sysfs file */ 43511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void 43611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertcpulist_read_from(CpuList* list, const char* filename) 43711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 43811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char file[64]; 43911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int filelen; 44011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 44111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_init(list); 44211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 44311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert filelen = read_file(filename, file, sizeof file); 44411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (filelen < 0) { 44511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Could not read %s: %s\n", filename, strerror(errno)); 44611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return; 44711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 44811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 44911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_parse(list, file, filelen); 45011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 45111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__aarch64__) 45211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// see <uapi/asm/hwcap.h> kernel header 45311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_FP (1 << 0) 45411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_ASIMD (1 << 1) 45511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_AES (1 << 3) 45611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_PMULL (1 << 4) 45711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_SHA1 (1 << 5) 45811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_SHA2 (1 << 6) 45911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_CRC32 (1 << 7) 46011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 46111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 46211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__arm__) 46311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 46411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// See <asm/hwcap.h> kernel header. 46511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_VFP (1 << 6) 46611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_IWMMXT (1 << 9) 46711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_NEON (1 << 12) 46811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_VFPv3 (1 << 13) 46911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_VFPv3D16 (1 << 14) 47011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_VFPv4 (1 << 16) 47111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_IDIVA (1 << 17) 47211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_IDIVT (1 << 18) 47311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 47411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// see <uapi/asm/hwcap.h> kernel header 47511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP2_AES (1 << 0) 47611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP2_PMULL (1 << 1) 47711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP2_SHA1 (1 << 2) 47811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP2_SHA2 (1 << 3) 47911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP2_CRC32 (1 << 4) 48011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 48111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This is the list of 32-bit ARMv7 optional features that are _always_ 48211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// supported by ARMv8 CPUs, as mandated by the ARM Architecture Reference 48311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Manual. 48411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_SET_FOR_ARMV8 \ 48511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ( HWCAP_VFP | \ 48611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert HWCAP_NEON | \ 48711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert HWCAP_VFPv3 | \ 48811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert HWCAP_VFPv4 | \ 48911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert HWCAP_IDIVA | \ 49011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert HWCAP_IDIVT ) 49111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 49211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 49311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__mips__) 49411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// see <uapi/asm/hwcap.h> kernel header 49511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_MIPS_R6 (1 << 0) 49611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define HWCAP_MIPS_MSA (1 << 1) 49711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 49811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 49911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__arm__) || defined(__aarch64__) || defined(__mips__) 50011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 50111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define AT_HWCAP 16 50211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define AT_HWCAP2 26 50311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 50411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Probe the system's C library for a 'getauxval' function and call it if 50511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// it exits, or return 0 for failure. This function is available since API 50611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// level 20. 50711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// 50811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the 50911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// edge case where some NDK developers use headers for a platform that is 51011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// newer than the one really targetted by their application. 51111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// This is typically done to use newer native APIs only when running on more 51211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// recent Android versions, and requires careful symbol management. 51311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// 51411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Note that getauxval() can't really be re-implemented here, because 51511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// its implementation does not parse /proc/self/auxv. Instead it depends 51611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// on values that are passed by the kernel at process-init time to the 51711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// C runtime initialization layer. 51811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t 51911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertget_elf_hwcap_from_getauxval(int hwcap_type) { 52011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert typedef unsigned long getauxval_func_t(unsigned long); 52111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 52211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert dlerror(); 52311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert void* libc_handle = dlopen("libc.so", RTLD_NOW); 52411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!libc_handle) { 52511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Could not dlopen() C library: %s\n", dlerror()); 52611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 52711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 52811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 52911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t ret = 0; 53011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert getauxval_func_t* func = (getauxval_func_t*) 53111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert dlsym(libc_handle, "getauxval"); 53211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!func) { 53311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Could not find getauxval() in C library\n"); 53411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } else { 53511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Note: getauxval() returns 0 on failure. Doesn't touch errno. 53611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ret = (uint32_t)(*func)(hwcap_type); 53711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 53811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert dlclose(libc_handle); 53911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return ret; 54011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 54111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 54211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 54311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__arm__) 54411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// Parse /proc/self/auxv to extract the ELF HW capabilities bitmap for the 54511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// current CPU. Note that this file is not accessible from regular 54611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// application processes on some Android platform releases. 54711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert// On success, return new ELF hwcaps, or 0 on failure. 54811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t 54911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertget_elf_hwcap_from_proc_self_auxv(void) { 55011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char filepath[] = "/proc/self/auxv"; 55111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int fd = TEMP_FAILURE_RETRY(open(filepath, O_RDONLY)); 55211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (fd < 0) { 55311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Could not open %s: %s\n", filepath, strerror(errno)); 55411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 55511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 55611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 55711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert struct { uint32_t tag; uint32_t value; } entry; 55811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 55911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t result = 0; 56011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (;;) { 56111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int ret = TEMP_FAILURE_RETRY(read(fd, (char*)&entry, sizeof entry)); 56211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret < 0) { 56311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Error while reading %s: %s\n", filepath, strerror(errno)); 56411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 56511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 56611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Detect end of list. 56711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (ret == 0 || (entry.tag == 0 && entry.value == 0)) 56811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 56911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (entry.tag == AT_HWCAP) { 57011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert result = entry.value; 57111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert break; 57211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 57311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 57411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert close(fd); 57511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return result; 57611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 57711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 57811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Compute the ELF HWCAP flags from the content of /proc/cpuinfo. 57911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * This works by parsing the 'Features' line, which lists which optional 58011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * features the device's CPU supports, on top of its reference 58111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * architecture. 58211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 58311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic uint32_t 58411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertget_elf_hwcap_from_proc_cpuinfo(const char* cpuinfo, int cpuinfo_len) { 58511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t hwcaps = 0; 58611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert long architecture = 0; 58711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); 58811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuArch) { 58911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert architecture = strtol(cpuArch, NULL, 10); 59011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuArch); 59111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 59211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (architecture >= 8L) { 59311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // This is a 32-bit ARM binary running on a 64-bit ARM64 kernel. 59411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // The 'Features' line only lists the optional features that the 59511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // device's CPU supports, compared to its reference architecture 59611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // which are of no use for this process. 59711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Faking 32-bit ARM HWCaps on ARMv%ld CPU\n", architecture); 59811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return HWCAP_SET_FOR_ARMV8; 59911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 60011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 60111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 60211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features"); 60311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuFeatures != NULL) { 60411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Found cpuFeatures = '%s'\n", cpuFeatures); 60511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 60611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "vfp")) 60711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_VFP; 60811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "vfpv3")) 60911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_VFPv3; 61011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "vfpv3d16")) 61111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_VFPv3D16; 61211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "vfpv4")) 61311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_VFPv4; 61411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "neon")) 61511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_NEON; 61611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "idiva")) 61711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_IDIVA; 61811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "idivt")) 61911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_IDIVT; 62011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "idiv")) 62111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_IDIVA | HWCAP_IDIVT; 62211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuFeatures, "iwmmxt")) 62311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps |= HWCAP_IWMMXT; 62411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 62511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuFeatures); 62611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 62711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return hwcaps; 62811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 62911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __arm__ */ 63011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 63111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Return the number of cpus present on a given device. 63211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 63311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * To handle all weird kernel configurations, we need to compute the 63411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * intersection of the 'present' and 'possible' CPU lists and count 63511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the result. 63611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 63711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic int 63811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertget_cpu_count(void) 63911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 64011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert CpuList cpus_present[1]; 64111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert CpuList cpus_possible[1]; 64211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 64311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present"); 64411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible"); 64511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 64611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Compute the intersection of both sets to get the actual number of 64711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * CPU cores that can be used on this device by the kernel. 64811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 64911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpulist_and(cpus_present, cpus_possible); 65011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 65111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return cpulist_count(cpus_present); 65211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 65311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 65411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void 65511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_cpuInitFamily(void) 65611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 65711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__arm__) 65811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_ARM; 65911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__i386__) 66011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_X86; 66111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__mips64) 66211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* Needs to be before __mips__ since the compiler defines both */ 66311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_MIPS64; 66411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__mips__) 66511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_MIPS; 66611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__aarch64__) 66711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_ARM64; 66811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#elif defined(__x86_64__) 66911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_X86_64; 67011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#else 67111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN; 67211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 67311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 67411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 67511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void 67611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_cpuInit(void) 67711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 67811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* cpuinfo = NULL; 67911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int cpuinfo_len; 68011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 68111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert android_cpuInitFamily(); 68211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 68311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures = 0; 68411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuCount = 1; 68511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_inited = 1; 68611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 68711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo_len = get_file_size("/proc/cpuinfo"); 68811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuinfo_len < 0) { 68911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("cpuinfo_len cannot be computed!"); 69011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return; 69111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 69211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo = malloc(cpuinfo_len); 69311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuinfo == NULL) { 69411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("cpuinfo buffer could not be allocated"); 69511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return; 69611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 69711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len); 69811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, 69911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); 70011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 70111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuinfo_len < 0) /* should not happen */ { 70211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuinfo); 70311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return; 70411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 70511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 70611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Count the CPU cores, the value may be 0 for single-core CPUs */ 70711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuCount = get_cpu_count(); 70811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (g_cpuCount == 0) { 70911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuCount = 1; 71011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 71111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 71211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("found cpuCount = %d\n", g_cpuCount); 71311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 71411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __arm__ 71511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { 71611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract architecture from the "CPU Architecture" field. 71711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * The list is well-known, unlike the the output of 71811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the 'Processor' field which can vary greatly. 71911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 72011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * See the definition of the 'proc_arch' array in 72111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in 72211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * same file. 72311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 72411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); 72511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 72611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuArch != NULL) { 72711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* end; 72811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert long archNumber; 72911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int hasARMv7 = 0; 73011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 73111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("found cpuArch = '%s'\n", cpuArch); 73211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 73311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* read the initial decimal number, ignore the rest */ 73411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert archNumber = strtol(cpuArch, &end, 10); 73511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 73611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Note that ARMv8 is upwards compatible with ARMv7. */ 73711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (end > cpuArch && archNumber >= 7) { 73811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hasARMv7 = 1; 73911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 74011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 74111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Unfortunately, it seems that certain ARMv6-based CPUs 74211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * report an incorrect architecture number of 7! 74311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 74411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * See http://code.google.com/p/android/issues/detail?id=10812 74511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 74611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * We try to correct this by looking at the 'elf_format' 74711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * field reported by the 'Processor' field, which is of the 74811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for 74911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * an ARMv6-one. 75011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 75111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hasARMv7) { 75211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, 75311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "Processor"); 75411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (cpuProc != NULL) { 75511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("found cpuProc = '%s'\n", cpuProc); 75611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_list_item(cpuProc, "(v6l)")) { 75711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("CPU processor and architecture mismatch!!\n"); 75811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hasARMv7 = 0; 75911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 76011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuProc); 76111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 76211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 76311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 76411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hasARMv7) { 76511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; 76611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 76711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 76811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* The LDREX / STREX instructions are available from ARMv6 */ 76911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (archNumber >= 6) { 77011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; 77111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 77211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 77311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuArch); 77411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 77511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 77611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract the list of CPU features from ELF hwcaps */ 77711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t hwcaps = 0; 77811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP); 77911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!hwcaps) { 78011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Parsing /proc/self/auxv to extract ELF hwcaps!\n"); 78111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps = get_elf_hwcap_from_proc_self_auxv(); 78211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 78311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!hwcaps) { 78411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Parsing /proc/self/auxv will fail from regular application 78511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // processes on some Android platform versions, when this happens 78611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // parse proc/cpuinfo instead. 78711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Parsing /proc/cpuinfo to extract ELF hwcaps!\n"); 78811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps = get_elf_hwcap_from_proc_cpuinfo(cpuinfo, cpuinfo_len); 78911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 79011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 79111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hwcaps != 0) { 79211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_vfp = (hwcaps & HWCAP_VFP); 79311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_vfpv3 = (hwcaps & HWCAP_VFPv3); 79411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_vfpv3d16 = (hwcaps & HWCAP_VFPv3D16); 79511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_vfpv4 = (hwcaps & HWCAP_VFPv4); 79611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_neon = (hwcaps & HWCAP_NEON); 79711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_idiva = (hwcaps & HWCAP_IDIVA); 79811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_idivt = (hwcaps & HWCAP_IDIVT); 79911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_iwmmxt = (hwcaps & HWCAP_IWMMXT); 80011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 80111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // The kernel does a poor job at ensuring consistency when 80211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // describing CPU features. So lots of guessing is needed. 80311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 80411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 'vfpv4' implies VFPv3|VFP_FMA|FP16 80511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_vfpv4) 80611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | 80711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_VFP_FP16 | 80811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_VFP_FMA; 80911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 81011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 'vfpv3' or 'vfpv3d16' imply VFPv3. Note that unlike GCC, 81111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // a value of 'vfpv3' doesn't necessarily mean that the D32 81211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // feature is present, so be conservative. All CPUs in the 81311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // field that support D32 also support NEON, so this should 81411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // not be a problem in practice. 81511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_vfpv3 || has_vfpv3d16) 81611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; 81711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 81811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // 'vfp' is super ambiguous. Depending on the kernel, it can 81911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // either mean VFPv2 or VFPv3. Make it depend on ARMv7. 82011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_vfp) { 82111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_ARMv7) 82211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; 82311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert else 82411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2; 82511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 82611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 82711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Neon implies VFPv3|D32, and if vfpv4 is detected, NEON_FMA 82811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_neon) { 82911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | 83011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_NEON | 83111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_VFP_D32; 83211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_vfpv4) 83311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA; 83411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 83511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 83611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // VFPv3 implies VFPv2 and ARMv7 83711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_VFPv3) 83811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2 | 83911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_ARMv7; 84011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 84111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_idiva) 84211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM; 84311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_idivt) 84411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2; 84511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 84611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_iwmmxt) 84711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt; 84811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 84911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 85011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract the list of CPU features from ELF hwcaps2 */ 85111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t hwcaps2 = 0; 85211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps2 = get_elf_hwcap_from_getauxval(AT_HWCAP2); 85311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hwcaps2 != 0) { 85411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_aes = (hwcaps2 & HWCAP2_AES); 85511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_pmull = (hwcaps2 & HWCAP2_PMULL); 85611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_sha1 = (hwcaps2 & HWCAP2_SHA1); 85711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_sha2 = (hwcaps2 & HWCAP2_SHA2); 85811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_crc32 = (hwcaps2 & HWCAP2_CRC32); 85911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 86011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_aes) 86111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES; 86211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_pmull) 86311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL; 86411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_sha1) 86511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1; 86611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_sha2) 86711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2; 86811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_crc32) 86911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32; 87011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 87111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract the cpuid value from various fields */ 87211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // The CPUID value is broken up in several entries in /proc/cpuinfo. 87311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // This table is used to rebuild it from the entries. 87411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert static const struct CpuIdEntry { 87511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* field; 87611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char format; 87711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char bit_lshift; 87811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char bit_length; 87911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } cpu_id_entries[] = { 88011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { "CPU implementer", 'x', 24, 8 }, 88111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { "CPU variant", 'x', 20, 4 }, 88211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { "CPU part", 'x', 4, 12 }, 88311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { "CPU revision", 'd', 0, 4 }, 88411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert }; 88511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert size_t i; 88611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("Parsing /proc/cpuinfo to recover CPUID\n"); 88711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (i = 0; 88811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]); 88911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ++i) { 89011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const struct CpuIdEntry* entry = &cpu_id_entries[i]; 89111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* value = extract_cpuinfo_field(cpuinfo, 89211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo_len, 89311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert entry->field); 89411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (value == NULL) 89511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert continue; 89611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 89711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("field=%s value='%s'\n", entry->field, value); 89811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* value_end = value + strlen(value); 89911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int val = 0; 90011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* start = value; 90111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const char* p; 90211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { 90311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert start += 2; 90411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = parse_hexadecimal(start, value_end, &val); 90511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } else if (entry->format == 'x') 90611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = parse_hexadecimal(value, value_end, &val); 90711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert else 90811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert p = parse_decimal(value, value_end, &val); 90911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 91011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (p > (const char*)start) { 91111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert val &= ((1 << entry->bit_length)-1); 91211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert val <<= entry->bit_lshift; 91311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuIdArm |= (uint32_t) val; 91411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 91511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 91611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(value); 91711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 91811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 91911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Handle kernel configuration bugs that prevent the correct 92011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // reporting of CPU features. 92111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert static const struct CpuFix { 92211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t cpuid; 92311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint64_t or_flags; 92411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } cpu_fixes[] = { 92511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* The Nexus 4 (Qualcomm Krait) kernel configuration 92611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * forgets to report IDIV support. */ 92711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { 0x510006f2, ANDROID_CPU_ARM_FEATURE_IDIV_ARM | 92811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 }, 92911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { 0x510006f3, ANDROID_CPU_ARM_FEATURE_IDIV_ARM | 93011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 }, 93111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert }; 93211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert size_t n; 93311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert for (n = 0; n < sizeof(cpu_fixes)/sizeof(cpu_fixes[0]); ++n) { 93411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert const struct CpuFix* entry = &cpu_fixes[n]; 93511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 93611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (g_cpuIdArm == entry->cpuid) 93711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= entry->or_flags; 93811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 93911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 94011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Special case: The emulator-specific Android 4.2 kernel fails 94111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // to report support for the 32-bit ARM IDIV instruction. 94211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // Technically, this is a feature of the virtual CPU implemented 94311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // by the emulator. Note that it could also support Thumb IDIV 94411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert // in the future, and this will have to be slightly updated. 94511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert char* hardware = extract_cpuinfo_field(cpuinfo, 94611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert cpuinfo_len, 94711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert "Hardware"); 94811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hardware) { 94911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!strcmp(hardware, "Goldfish") && 95011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuIdArm == 0x4100c080 && 95111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert (g_cpuFamily & ANDROID_CPU_ARM_FEATURE_ARMv7) != 0) { 95211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM; 95311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 95411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(hardware); 95511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 95611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 95711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __arm__ */ 95811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __aarch64__ 95911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { 96011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract the list of CPU features from ELF hwcaps */ 96111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t hwcaps = 0; 96211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP); 96311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hwcaps != 0) { 96411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_fp = (hwcaps & HWCAP_FP); 96511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_asimd = (hwcaps & HWCAP_ASIMD); 96611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_aes = (hwcaps & HWCAP_AES); 96711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_pmull = (hwcaps & HWCAP_PMULL); 96811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_sha1 = (hwcaps & HWCAP_SHA1); 96911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_sha2 = (hwcaps & HWCAP_SHA2); 97011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_crc32 = (hwcaps & HWCAP_CRC32); 97111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 97211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if(has_fp == 0) { 97311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("ERROR: Floating-point unit missing, but is required by Android on AArch64 CPUs\n"); 97411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 97511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if(has_asimd == 0) { 97611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert D("ERROR: ASIMD unit missing, but is required by Android on AArch64 CPUs\n"); 97711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 97811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 97911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_fp) 98011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP; 98111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_asimd) 98211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD; 98311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_aes) 98411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES; 98511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_pmull) 98611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL; 98711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_sha1) 98811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1; 98911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_sha2) 99011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2; 99111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_crc32) 99211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32; 99311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 99411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 99511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __aarch64__ */ 99611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 99711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined(__i386__) || defined(__x86_64__) 99811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int regs[4]; 99911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 100011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* According to http://en.wikipedia.org/wiki/CPUID */ 100111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define VENDOR_INTEL_b 0x756e6547 100211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define VENDOR_INTEL_c 0x6c65746e 100311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#define VENDOR_INTEL_d 0x49656e69 100411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 100511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert x86_cpuid(0, regs); 100611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int vendorIsIntel = (regs[1] == VENDOR_INTEL_b && 100711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert regs[2] == VENDOR_INTEL_c && 100811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert regs[3] == VENDOR_INTEL_d); 100911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 101011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert x86_cpuid(1, regs); 101111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 9)) != 0) { 101211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; 101311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 101411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 23)) != 0) { 101511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; 101611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 101711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 19)) != 0) { 101811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1; 101911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 102011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 20)) != 0) { 102111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2; 102211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 102311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) { 102411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; 102511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 102611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 25)) != 0) { 102711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI; 102811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 102911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 28)) != 0) { 103011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX; 103111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 103211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[2] & (1 << 30)) != 0) { 103311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND; 103411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 103511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 103611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert x86_cpuid(7, regs); 103711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[1] & (1 << 5)) != 0) { 103811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2; 103911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 104011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if ((regs[1] & (1 << 29)) != 0) { 104111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI; 104211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 104311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 104411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 104511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif 104611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#if defined( __mips__) 104711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert { /* MIPS and MIPS64 */ 104811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Extract the list of CPU features from ELF hwcaps */ 104911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert uint32_t hwcaps = 0; 105011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert hwcaps = get_elf_hwcap_from_getauxval(AT_HWCAP); 105111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (hwcaps != 0) { 105211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_r6 = (hwcaps & HWCAP_MIPS_R6); 105311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert int has_msa = (hwcaps & HWCAP_MIPS_MSA); 105411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_r6) 105511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6; 105611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (has_msa) 105711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA; 105811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 105911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert } 106011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __mips__ */ 106111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 106211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert free(cpuinfo); 106311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 106411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 106511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 106611cd02dfb91661c65134cac258cf5924270e9d2Dan AlbertAndroidCpuFamily 106711cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_getCpuFamily(void) 106811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 106911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pthread_once(&g_once, android_cpuInit); 107011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return g_cpuFamily; 107111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 107211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 107311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 107411cd02dfb91661c65134cac258cf5924270e9d2Dan Albertuint64_t 107511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_getCpuFeatures(void) 107611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 107711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pthread_once(&g_once, android_cpuInit); 107811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return g_cpuFeatures; 107911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 108011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 108111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 108211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertint 108311cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_getCpuCount(void) 108411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 108511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pthread_once(&g_once, android_cpuInit); 108611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return g_cpuCount; 108711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 108811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 108911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertstatic void 109011cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_cpuInitDummy(void) 109111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 109211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_inited = 1; 109311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 109411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 109511cd02dfb91661c65134cac258cf5924270e9d2Dan Albertint 109611cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_setCpu(int cpu_count, uint64_t cpu_features) 109711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 109811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert /* Fail if the library was already initialized. */ 109911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (g_inited) 110011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 110111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 110211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert android_cpuInitFamily(); 110311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count); 110411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuFeatures = cpu_features; 110511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pthread_once(&g_once, android_cpuInitDummy); 110611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 110711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 1; 110811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 110911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 111011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#ifdef __arm__ 111111cd02dfb91661c65134cac258cf5924270e9d2Dan Albertuint32_t 111211cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_getCpuIdArm(void) 111311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 111411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert pthread_once(&g_once, android_cpuInit); 111511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return g_cpuIdArm; 111611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 111711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 111811cd02dfb91661c65134cac258cf5924270e9d2Dan Albertint 111911cd02dfb91661c65134cac258cf5924270e9d2Dan Albertandroid_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) 112011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert{ 112111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert if (!android_setCpu(cpu_count, cpu_features)) 112211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 0; 112311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 112411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert g_cpuIdArm = cpu_id; 112511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert return 1; 112611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert} 112711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#endif /* __arm__ */ 112811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 112911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/* 113011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Technical note: Making sense of ARM's FPU architecture versions. 113111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 113211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPA was ARM's first attempt at an FPU architecture. There is no Android 113311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * device that actually uses it since this technology was already obsolete 113411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * when the project started. If you see references to FPA instructions 113511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * somewhere, you can be sure that this doesn't apply to Android at all. 113611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 113711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPA was followed by "VFP", soon renamed "VFPv1" due to the emergence of 113811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * new versions / additions to it. ARM considers this obsolete right now, 113911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * and no known Android device implements it either. 114011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 114111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv2 added a few instructions to VFPv1, and is an *optional* extension 114211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * supported by some ARMv5TE, ARMv6 and ARMv6T2 CPUs. Note that a device 114311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * supporting the 'armeabi' ABI doesn't necessarily support these. 114411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 114511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv3-D16 adds a few instructions on top of VFPv2 and is typically used 114611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * on ARMv7-A CPUs which implement a FPU. Note that it is also mandated 114711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * by the Android 'armeabi-v7a' ABI. The -D16 suffix in its name means 114811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * that it provides 16 double-precision FPU registers (d0-d15) and 32 114911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * single-precision ones (s0-s31) which happen to be mapped to the same 115011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * register banks. 115111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 115211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv3-D32 is the name of an extension to VFPv3-D16 that provides 16 115311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * additional double precision registers (d16-d31). Note that there are 115411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * still only 32 single precision registers. 115511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 115611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv3xD is a *subset* of VFPv3-D16 that only provides single-precision 115711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * registers. It is only used on ARMv7-M (i.e. on micro-controllers) which 115811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * are not supported by Android. Note that it is not compatible with VFPv2. 115911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 116011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NOTE: The term 'VFPv3' usually designate either VFPv3-D16 or VFPv3-D32 116111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * depending on context. For example GCC uses it for VFPv3-D32, but 116211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * the Linux kernel code uses it for VFPv3-D16 (especially in 116311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * /proc/cpuinfo). Always try to use the full designation when 116411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * possible. 116511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 116611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NEON, a.k.a. "ARM Advanced SIMD" is an extension that provides 116711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * instructions to perform parallel computations on vectors of 8, 16, 116811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 32, 64 and 128 bit quantities. NEON requires VFPv32-D32 since all 116911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NEON registers are also mapped to the same register banks. 117011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 117111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv4-D16, adds a few instructions on top of VFPv3-D16 in order to 117211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * perform fused multiply-accumulate on VFP registers, as well as 117311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * half-precision (16-bit) conversion operations. 117411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 117511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFPv4-D32 is VFPv4-D16 with 32, instead of 16, FPU double precision 117611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * registers. 117711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 117811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VPFv4-NEON is VFPv4-D32 with NEON instructions. It also adds fused 117911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * multiply-accumulate instructions that work on the NEON registers. 118011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 118111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * NOTE: Similarly, "VFPv4" might either reference VFPv4-D16 or VFPv4-D32 118211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * depending on context. 118311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 118411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * The following information was determined by scanning the binutils-2.22 118511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * sources: 118611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 118711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Basic VFP instruction subsets: 118811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 118911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_V1xD 0x08000000 // Base VFP instruction set. 119011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_V1 0x04000000 // Double-precision insns. 119111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_V2 0x02000000 // ARM10E VFPr1. 119211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_V3xD 0x01000000 // VFPv3 single-precision. 119311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_V3 0x00800000 // VFPv3 double-precision. 119411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_NEON_EXT_V1 0x00400000 // Neon (SIMD) insns. 119511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_D32 0x00200000 // Registers D16-D31. 119611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_FP16 0x00100000 // Half-precision extensions. 119711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_NEON_EXT_FMA 0x00080000 // Neon fused multiply-add 119811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * #define FPU_VFP_EXT_FMA 0x00040000 // VFP fused multiply-add 119911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 120011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU types (excluding NEON) 120111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 120211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_V1xD (EXT_V1xD) 120311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 120411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +--------------------------+ 120511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 120611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_V1 (+EXT_V1) FPU_VFP_V3xD (+EXT_V2+EXT_V3xD) 120711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 120811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 120911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_V2 (+EXT_V2) FPU_VFP_V4_SP_D16 (+EXT_FP16+EXT_FMA) 121011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 121111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_V3D16 (+EXT_Vx3D+EXT_V3) 121211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 121311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +--------------------------+ 121411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 121511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_V3 (+EXT_D32) FPU_VFP_V4D16 (+EXT_FP16+EXT_FMA) 121611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 121711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | FPU_VFP_V4 (+EXT_D32) 121811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 121911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * FPU_VFP_HARD (+EXT_FMA+NEON_EXT_FMA) 122011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 122111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * VFP architectures: 122211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 122311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V1xD (EXT_V1xD) 122411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 122511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +------------------+ 122611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 122711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3xD (+EXT_V2+EXT_V3xD) 122811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 122911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3xD_FP16 (+EXT_FP16) 123011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 123111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V4_SP_D16 (+EXT_FMA) 123211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 123311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V1 (+EXT_V1) 123411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 123511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V2 (+EXT_V2) 123611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 123711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3D16 (+EXT_V3xD+EXT_V3) 123811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 123911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 124011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 124111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3D16_FP16 (+EXT_FP16) 124211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 124311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 124411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 124511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA) 124611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 124711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V4 (+EXT_D32) 124811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 124911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA) 125011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 125111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3 (+EXT_D32) 125211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 125311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 125411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 125511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3_FP16 (+EXT_FP16) 125611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 125711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON) 125811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 125911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_NEON_FP16 (+EXT_FP16) 126011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 126111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * -fpu=<name> values and their correspondance with FPU architectures above: 126211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 126311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfp", FPU_ARCH_VFP_V2}, 126411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfp9", FPU_ARCH_VFP_V2}, 126511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfp3", FPU_ARCH_VFP_V3}, // For backwards compatbility. 126611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfp10", FPU_ARCH_VFP_V2}, 126711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfp10-r0", FPU_ARCH_VFP_V1}, 126811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpxd", FPU_ARCH_VFP_V1xD}, 126911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv2", FPU_ARCH_VFP_V2}, 127011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3", FPU_ARCH_VFP_V3}, 127111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3-fp16", FPU_ARCH_VFP_V3_FP16}, 127211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3-d16", FPU_ARCH_VFP_V3D16}, 127311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16}, 127411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3xd", FPU_ARCH_VFP_V3xD}, 127511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16}, 127611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1}, 127711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"neon-fp16", FPU_ARCH_NEON_FP16}, 127811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv4", FPU_ARCH_VFP_V4}, 127911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"vfpv4-d16", FPU_ARCH_VFP_V4D16}, 128011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"fpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16}, 128111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * {"neon-vfpv4", FPU_ARCH_NEON_VFP_V4}, 128211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 128311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 128411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Simplified diagram that only includes FPUs supported by Android: 128511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * Only ARCH_VFP_V3D16 is actually mandated by the armeabi-v7a ABI, 128611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * all others are optional and must be probed at runtime. 128711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 128811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3D16 (EXT_V1xD+EXT_V1+EXT_V2+EXT_V3xD+EXT_V3) 128911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 129011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 129111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 129211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3D16_FP16 (+EXT_FP16) 129311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 129411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 129511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 129611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA) 129711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 129811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V4 (+EXT_D32) 129911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 130011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA) 130111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 130211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3 (+EXT_D32) 130311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 130411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * +-------------------+ 130511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | | 130611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | ARCH_VFP_V3_FP16 (+EXT_FP16) 130711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 130811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON) 130911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * | 131011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * ARCH_NEON_FP16 (+EXT_FP16) 131111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert * 131211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert */ 1313