@ -27,6 +27,10 @@
*/
/* ChangeLog for this library:
*
* NDK r10e ? : Add MIPS MSA feature .
*
* NDK r10 : Support for 64 - bit CPUs ( Intel , ARM & MIPS ) .
*
* NDK r8d : Add android_setCpu ( ) .
*
@ -56,16 +60,17 @@
*
* NDK r4 : Initial release
*/
# include <sys/system_properties.h>
# ifdef __arm__
# include <machine/cpu-features.h>
# endif
# include <pthread.h>
# include "cpu-features.h"
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <fcntl.h>
# include <errno.h>
# include <sys/system_properties .h>
# include <unistd .h>
static pthread_once_t g_once ;
static int g_inited ;
@ -73,16 +78,12 @@ static AndroidCpuFamily g_cpuFamily;
static uint64_t g_cpuFeatures ;
static int g_cpuCount ;
static const int android_cpufeatures_debug = 0 ;
# ifdef __arm__
# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
# elif defined __i386__
# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
# else
# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
static uint32_t g_cpuIdArm ;
# endif
static const int android_cpufeatures_debug = 0 ;
# define D(...) \
do { \
if ( android_cpufeatures_debug ) { \
@ -109,6 +110,25 @@ static __inline__ void x86_cpuid(int func, int values[4])
values [ 2 ] = c ;
values [ 3 ] = d ;
}
# elif defined(__x86_64__)
static __inline__ void x86_cpuid ( int func , int values [ 4 ] )
{
int64_t a , b , c , d ;
/* We need to preserve ebx since we're compiling PIC code */
/* this means we can't use "=b" for the second output register */
__asm__ __volatile__ ( \
" push %%rbx \n "
" cpuid \n " \
" mov %%rbx, %1 \n "
" pop %%rbx \n "
: " =a " ( a ) , " =r " ( b ) , " =c " ( c ) , " =d " ( d ) \
: " a " ( func ) \
) ;
values [ 0 ] = a ;
values [ 1 ] = b ;
values [ 2 ] = c ;
values [ 3 ] = d ;
}
# endif
/* Get the size of a file by reading it until the end. This is needed
@ -118,7 +138,8 @@ static __inline__ void x86_cpuid(int func, int values[4])
static int
get_file_size ( const char * pathname )
{
int fd , ret , result = 0 ;
int fd , result = 0 ;
char buffer [ 256 ] ;
fd = open ( pathname , O_RDONLY ) ;
@ -178,6 +199,7 @@ read_file(const char* pathname, char* buffer, size_t buffsize)
return count ;
}
# ifdef __arm__
/* Extract the content of a the first occurence of a given field in
* the content of / proc / cpuinfo and return it as a heap - allocated
* string that must be freed by the caller .
@ -190,12 +212,11 @@ extract_cpuinfo_field(const char* buffer, int buflen, const char* field)
int fieldlen = strlen ( field ) ;
const char * bufend = buffer + buflen ;
char * result = NULL ;
int len , ignore ;
int len ;
const char * p , * q ;
/* Look for first field occurence, and ensures it starts the line. */
p = buffer ;
bufend = buffer + buflen ;
for ( ; ; ) {
p = memmem ( p , bufend - p , field , fieldlen ) ;
if ( p = = NULL )
@ -232,10 +253,6 @@ EXIT:
return result ;
}
/* Like strlen(), but for constant string literals */
# define STRLEN_CONST(x) ((sizeof(x)-1)
/* Checks that a space-separated list of items contains one given 'item'.
* Returns 1 if found , 0 otherwise .
*/
@ -268,8 +285,9 @@ has_list_item(const char* list, const char* item)
}
return 0 ;
}
# endif /* __arm__ */
/* Parse an decimal integ er starting from 'input', but not going further
/* Parse a numb er starting from 'input', but not going further
* than ' limit ' . Return the value into ' * result ' .
*
* NOTE : Does not skip over leading spaces , or deal with sign characters .
@ -280,15 +298,23 @@ has_list_item(const char* list, const char* item)
* be < = ' limit ' ) .
*/
static const char *
parse_decimal ( const char * input , const char * limit , int * result )
parse_number ( const char * input , const char * limit , int base , int * result )
{
const char * p = input ;
int val = 0 ;
while ( p < limit ) {
int d = ( * p - ' 0 ' ) ;
if ( ( unsigned ) d > = 10U )
break ;
val = val * 10 + d ;
if ( ( unsigned ) d > = 10U ) {
d = ( * p - ' a ' ) ;
if ( ( unsigned ) d > = 6U )
d = ( * p - ' A ' ) ;
if ( ( unsigned ) d > = 6U )
break ;
d + = 10 ;
}
if ( d > = base )
break ;
val = val * base + d ;
p + + ;
}
if ( p = = input )
@ -298,6 +324,20 @@ parse_decimal(const char* input, const char* limit, int* result)
return p ;
}
static const char *
parse_decimal ( const char * input , const char * limit , int * result )
{
return parse_number ( input , limit , 10 , result ) ;
}
# ifdef __arm__
static const char *
parse_hexadecimal ( const char * input , const char * limit , int * result )
{
return parse_number ( input , limit , 16 , result ) ;
}
# endif /* __arm__ */
/* This small data type is used to represent a CPU list / mask, as read
* from sysfs on Linux . See http : //www.kernel.org/doc/Documentation/cputopology.txt
*
@ -408,6 +448,18 @@ cpulist_read_from(CpuList* list, const char* filename)
cpulist_parse ( list , file , filelen ) ;
}
# if defined(__aarch64__)
// see <uapi/asm/hwcap.h> kernel header
# define HWCAP_FP (1 << 0)
# define HWCAP_ASIMD (1 << 1)
# define HWCAP_AES (1 << 3)
# define HWCAP_PMULL (1 << 4)
# define HWCAP_SHA1 (1 << 5)
# define HWCAP_SHA2 (1 << 6)
# define HWCAP_CRC32 (1 << 7)
# endif
# if defined(__arm__)
// See <asm/hwcap.h> kernel header.
# define HWCAP_VFP (1 << 6)
@ -419,27 +471,104 @@ cpulist_read_from(CpuList* list, const char* filename)
# define HWCAP_IDIVA (1 << 17)
# define HWCAP_IDIVT (1 << 18)
// see <uapi/asm/hwcap.h> kernel header
# define HWCAP2_AES (1 << 0)
# define HWCAP2_PMULL (1 << 1)
# define HWCAP2_SHA1 (1 << 2)
# define HWCAP2_SHA2 (1 << 3)
# define HWCAP2_CRC32 (1 << 4)
// This is the list of 32-bit ARMv7 optional features that are _always_
// supported by ARMv8 CPUs, as mandated by the ARM Architecture Reference
// Manual.
# define HWCAP_SET_FOR_ARMV8 \
( HWCAP_VFP | \
HWCAP_NEON | \
HWCAP_VFPv3 | \
HWCAP_VFPv4 | \
HWCAP_IDIVA | \
HWCAP_IDIVT )
# endif
# if defined(__mips__)
// see <uapi/asm/hwcap.h> kernel header
# define HWCAP_MIPS_R6 (1 << 0)
# define HWCAP_MIPS_MSA (1 << 1)
# endif
# if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
# define AT_HWCAP 16
# define AT_HWCAP2 26
// Probe the system's C library for a 'getauxval' function and call it if
// it exits, or return 0 for failure. This function is available since API
// level 20.
//
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the
// edge case where some NDK developers use headers for a platform that is
// newer than the one really targetted by their application.
// This is typically done to use newer native APIs only when running on more
// recent Android versions, and requires careful symbol management.
//
// Note that getauxval() can't really be re-implemented here, because
// its implementation does not parse /proc/self/auxv. Instead it depends
// on values that are passed by the kernel at process-init time to the
// C runtime initialization layer.
# if 1
// OpenCV calls CPU features check during library initialization stage
// (under other dlopen() call).
// Unfortunatelly, calling dlopen() recursively is not supported on some old
// Android versions. Android fix is here:
// - https://android-review.googlesource.com/#/c/32951/
// - GitHub mirror: https://github.com/android/platform_bionic/commit/e19d702b8e330cef87e0983733c427b5f7842144
__attribute__ ( ( weak ) ) unsigned long getauxval ( unsigned long ) ; // Lets linker to handle this symbol
static uint32_t
get_elf_hwcap_from_getauxval ( int hwcap_type ) {
uint32_t ret = 0 ;
if ( getauxval ! = 0 ) {
ret = ( uint32_t ) getauxval ( hwcap_type ) ;
} else {
D ( " getauxval() is not available \n " ) ;
}
return ret ;
}
# else
static uint32_t
get_elf_hwcap_from_getauxval ( int hwcap_type ) {
typedef unsigned long getauxval_func_t ( unsigned long ) ;
dlerror ( ) ;
void * libc_handle = dlopen ( " libc.so " , RTLD_NOW ) ;
if ( ! libc_handle ) {
D ( " Could not dlopen() C library: %s \n " , dlerror ( ) ) ;
return 0 ;
}
uint32_t ret = 0 ;
getauxval_func_t * func = ( getauxval_func_t * )
dlsym ( libc_handle , " getauxval " ) ;
if ( ! func ) {
D ( " Could not find getauxval() in C library \n " ) ;
} else {
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
ret = ( uint32_t ) ( * func ) ( hwcap_type ) ;
}
dlclose ( libc_handle ) ;
return ret ;
}
# endif
# endif
# if defined(__arm__)
/* Compute the ELF HWCAP flags.
*/
// Parse /proc/self/auxv to extract the ELF HW capabilities bitmap for the
// current CPU. Note that this file is not accessible from regular
// application processes on some Android platform releases.
// On success, return new ELF hwcaps, or 0 on failure.
static uint32_t
get_elf_hwcap ( const char * cpuinfo , int cpuinfo_len )
{
/* IMPORTANT:
* Accessing / proc / self / auxv doesn ' t work anymore on all
* platform versions . More specifically , when running inside
* a regular application process , most of / proc / self / will be
* non - readable , including / proc / self / auxv . This doesn ' t
* happen however if the application is debuggable , or when
* running under the " shell " UID , which is why this was not
* detected appropriately .
*/
#if 0
uint32_t result = 0 ;
get_elf_hwcap_from_proc_self_auxv ( void ) {
const char filepath [ ] = " /proc/self/auxv " ;
int fd = open ( filepath , O_RDONLY ) ;
int fd = TEMP_FAILURE_RETRY ( open ( filepath , O_RDONLY ) ) ;
if ( fd < 0 ) {
D ( " Could not open %s: %s \n " , filepath , strerror ( errno ) ) ;
return 0 ;
@ -447,11 +576,10 @@ get_elf_hwcap(const char* cpuinfo, int cpuinfo_len)
struct { uint32_t tag ; uint32_t value ; } entry ;
uint32_t result = 0 ;
for ( ; ; ) {
int ret = read ( fd , ( char * ) & entry , sizeof entry ) ;
int ret = TEMP_FAILURE_RETRY ( read ( fd , ( char * ) & entry , sizeof entry ) ) ;
if ( ret < 0 ) {
if ( errno = = EINTR )
continue ;
D ( " Error while reading %s: %s \n " , filepath , strerror ( errno ) ) ;
break ;
}
@ -465,12 +593,33 @@ get_elf_hwcap(const char* cpuinfo, int cpuinfo_len)
}
close ( fd ) ;
return result ;
# else
// Recreate ELF hwcaps by parsing /proc/cpuinfo Features tag.
}
/* Compute the ELF HWCAP flags from the content of /proc/cpuinfo.
* This works by parsing the ' Features ' line , which lists which optional
* features the device ' s CPU supports , on top of its reference
* architecture .
*/
static uint32_t
get_elf_hwcap_from_proc_cpuinfo ( const char * cpuinfo , int cpuinfo_len ) {
uint32_t hwcaps = 0 ;
long architecture = 0 ;
char * cpuArch = extract_cpuinfo_field ( cpuinfo , cpuinfo_len , " CPU architecture " ) ;
if ( cpuArch ) {
architecture = strtol ( cpuArch , NULL , 10 ) ;
free ( cpuArch ) ;
if ( architecture > = 8L ) {
// This is a 32-bit ARM binary running on a 64-bit ARM64 kernel.
// The 'Features' line only lists the optional features that the
// device's CPU supports, compared to its reference architecture
// which are of no use for this process.
D ( " Faking 32-bit ARM HWCaps on ARMv%ld CPU \n " , architecture ) ;
return HWCAP_SET_FOR_ARMV8 ;
}
}
char * cpuFeatures = extract_cpuinfo_field ( cpuinfo , cpuinfo_len , " Features " ) ;
if ( cpuFeatures ! = NULL ) {
D ( " Found cpuFeatures = '%s' \n " , cpuFeatures ) ;
@ -496,7 +645,6 @@ get_elf_hwcap(const char* cpuinfo, int cpuinfo_len)
free ( cpuFeatures ) ;
}
return hwcaps ;
# endif
}
# endif /* __arm__ */
@ -526,12 +674,19 @@ get_cpu_count(void)
static void
android_cpuInitFamily ( void )
{
# if defined(__ARM_ARCH __)
# if defined(__arm __)
g_cpuFamily = ANDROID_CPU_FAMILY_ARM ;
# elif defined(__i386__)
g_cpuFamily = ANDROID_CPU_FAMILY_X86 ;
# elif defined(_MIPS_ARCH)
# elif defined(__mips64)
/* Needs to be before __mips__ since the compiler defines both */
g_cpuFamily = ANDROID_CPU_FAMILY_MIPS64 ;
# elif defined(__mips__)
g_cpuFamily = ANDROID_CPU_FAMILY_MIPS ;
# elif defined(__aarch64__)
g_cpuFamily = ANDROID_CPU_FAMILY_ARM64 ;
# elif defined(__x86_64__)
g_cpuFamily = ANDROID_CPU_FAMILY_X86_64 ;
# else
g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN ;
# endif
@ -576,11 +731,8 @@ android_cpuInit(void)
D ( " found cpuCount = %d \n " , g_cpuCount ) ;
# ifdef __ARM_ARCH __
# ifdef __arm __
{
char * features = NULL ;
char * architecture = NULL ;
/* Extract architecture from the "CPU Architecture" field.
* The list is well - known , unlike the the output of
* the ' Processor ' field which can vary greatly .
@ -601,10 +753,7 @@ android_cpuInit(void)
/* read the initial decimal number, ignore the rest */
archNumber = strtol ( cpuArch , & end , 10 ) ;
/* Here we assume that ARMv8 will be upwards compatible with v7
* in the future . Unfortunately , there is no ' Features ' field to
* indicate that Thumb - 2 is supported .
*/
/* Note that ARMv8 is upwards compatible with ARMv7. */
if ( end > cpuArch & & archNumber > = 7 ) {
hasARMv7 = 1 ;
}
@ -645,7 +794,19 @@ android_cpuInit(void)
}
/* Extract the list of CPU features from ELF hwcaps */
uint32_t hwcaps = get_elf_hwcap ( cpuinfo , cpuinfo_len ) ;
uint32_t hwcaps = 0 ;
hwcaps = get_elf_hwcap_from_getauxval ( AT_HWCAP ) ;
if ( ! hwcaps ) {
D ( " Parsing /proc/self/auxv to extract ELF hwcaps! \n " ) ;
hwcaps = get_elf_hwcap_from_proc_self_auxv ( ) ;
}
if ( ! hwcaps ) {
// Parsing /proc/self/auxv will fail from regular application
// processes on some Android platform versions, when this happens
// parse proc/cpuinfo instead.
D ( " Parsing /proc/cpuinfo to extract ELF hwcaps! \n " ) ;
hwcaps = get_elf_hwcap_from_proc_cpuinfo ( cpuinfo , cpuinfo_len ) ;
}
if ( hwcaps ! = 0 ) {
int has_vfp = ( hwcaps & HWCAP_VFP ) ;
@ -697,22 +858,163 @@ android_cpuInit(void)
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_VFPv2 |
ANDROID_CPU_ARM_FEATURE_ARMv7 ;
// Note that some buggy kernels do not report these even when
// the CPU actually support the division instructions. However,
// assume that if 'vfpv4' is detected, then the CPU supports
// sdiv/udiv properly.
if ( has_idiva | | has_vfpv4 )
if ( has_idiva )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_IDIV_ARM ;
if ( has_idivt | | has_vfpv4 )
if ( has_idivt )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 ;
if ( has_iwmmxt )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_iWMMXt ;
}
/* Extract the list of CPU features from ELF hwcaps2 */
uint32_t hwcaps2 = 0 ;
hwcaps2 = get_elf_hwcap_from_getauxval ( AT_HWCAP2 ) ;
if ( hwcaps2 ! = 0 ) {
int has_aes = ( hwcaps2 & HWCAP2_AES ) ;
int has_pmull = ( hwcaps2 & HWCAP2_PMULL ) ;
int has_sha1 = ( hwcaps2 & HWCAP2_SHA1 ) ;
int has_sha2 = ( hwcaps2 & HWCAP2_SHA2 ) ;
int has_crc32 = ( hwcaps2 & HWCAP2_CRC32 ) ;
if ( has_aes )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_AES ;
if ( has_pmull )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_PMULL ;
if ( has_sha1 )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_SHA1 ;
if ( has_sha2 )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_SHA2 ;
if ( has_crc32 )
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_CRC32 ;
}
/* Extract the cpuid value from various fields */
// The CPUID value is broken up in several entries in /proc/cpuinfo.
// This table is used to rebuild it from the entries.
static const struct CpuIdEntry {
const char * field ;
char format ;
char bit_lshift ;
char bit_length ;
} cpu_id_entries [ ] = {
{ " CPU implementer " , ' x ' , 24 , 8 } ,
{ " CPU variant " , ' x ' , 20 , 4 } ,
{ " CPU part " , ' x ' , 4 , 12 } ,
{ " CPU revision " , ' d ' , 0 , 4 } ,
} ;
size_t i ;
D ( " Parsing /proc/cpuinfo to recover CPUID \n " ) ;
for ( i = 0 ;
i < sizeof ( cpu_id_entries ) / sizeof ( cpu_id_entries [ 0 ] ) ;
+ + i ) {
const struct CpuIdEntry * entry = & cpu_id_entries [ i ] ;
char * value = extract_cpuinfo_field ( cpuinfo ,
cpuinfo_len ,
entry - > field ) ;
if ( value = = NULL )
continue ;
D ( " field=%s value='%s' \n " , entry - > field , value ) ;
char * value_end = value + strlen ( value ) ;
int val = 0 ;
const char * start = value ;
const char * p ;
if ( value [ 0 ] = = ' 0 ' & & ( value [ 1 ] = = ' x ' | | value [ 1 ] = = ' X ' ) ) {
start + = 2 ;
p = parse_hexadecimal ( start , value_end , & val ) ;
} else if ( entry - > format = = ' x ' )
p = parse_hexadecimal ( value , value_end , & val ) ;
else
p = parse_decimal ( value , value_end , & val ) ;
if ( p > ( const char * ) start ) {
val & = ( ( 1 < < entry - > bit_length ) - 1 ) ;
val < < = entry - > bit_lshift ;
g_cpuIdArm | = ( uint32_t ) val ;
}
free ( value ) ;
}
// Handle kernel configuration bugs that prevent the correct
// reporting of CPU features.
static const struct CpuFix {
uint32_t cpuid ;
uint64_t or_flags ;
} cpu_fixes [ ] = {
/* The Nexus 4 (Qualcomm Krait) kernel configuration
* forgets to report IDIV support . */
{ 0x510006f2 , ANDROID_CPU_ARM_FEATURE_IDIV_ARM |
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 } ,
{ 0x510006f3 , ANDROID_CPU_ARM_FEATURE_IDIV_ARM |
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 } ,
} ;
size_t n ;
for ( n = 0 ; n < sizeof ( cpu_fixes ) / sizeof ( cpu_fixes [ 0 ] ) ; + + n ) {
const struct CpuFix * entry = & cpu_fixes [ n ] ;
if ( g_cpuIdArm = = entry - > cpuid )
g_cpuFeatures | = entry - > or_flags ;
}
// Special case: The emulator-specific Android 4.2 kernel fails
// to report support for the 32-bit ARM IDIV instruction.
// Technically, this is a feature of the virtual CPU implemented
// by the emulator. Note that it could also support Thumb IDIV
// in the future, and this will have to be slightly updated.
char * hardware = extract_cpuinfo_field ( cpuinfo ,
cpuinfo_len ,
" Hardware " ) ;
if ( hardware ) {
if ( ! strcmp ( hardware , " Goldfish " ) & &
g_cpuIdArm = = 0x4100c080 & &
( g_cpuFamily & ANDROID_CPU_ARM_FEATURE_ARMv7 ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_ARM_FEATURE_IDIV_ARM ;
}
free ( hardware ) ;
}
}
# endif /* __arm__ */
# ifdef __aarch64__
{
/* Extract the list of CPU features from ELF hwcaps */
uint32_t hwcaps = 0 ;
hwcaps = get_elf_hwcap_from_getauxval ( AT_HWCAP ) ;
if ( hwcaps ! = 0 ) {
int has_fp = ( hwcaps & HWCAP_FP ) ;
int has_asimd = ( hwcaps & HWCAP_ASIMD ) ;
int has_aes = ( hwcaps & HWCAP_AES ) ;
int has_pmull = ( hwcaps & HWCAP_PMULL ) ;
int has_sha1 = ( hwcaps & HWCAP_SHA1 ) ;
int has_sha2 = ( hwcaps & HWCAP_SHA2 ) ;
int has_crc32 = ( hwcaps & HWCAP_CRC32 ) ;
if ( has_fp = = 0 ) {
D ( " ERROR: Floating-point unit missing, but is required by Android on AArch64 CPUs \n " ) ;
}
if ( has_asimd = = 0 ) {
D ( " ERROR: ASIMD unit missing, but is required by Android on AArch64 CPUs \n " ) ;
}
if ( has_fp )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_FP ;
if ( has_asimd )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_ASIMD ;
if ( has_aes )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_AES ;
if ( has_pmull )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_PMULL ;
if ( has_sha1 )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_SHA1 ;
if ( has_sha2 )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_SHA2 ;
if ( has_crc32 )
g_cpuFeatures | = ANDROID_CPU_ARM64_FEATURE_CRC32 ;
}
}
# endif /* __ARM_ARCH__ */
# endif /* __aarch64 __ */
# ifdef __i386__
# if defined(__i386__) || defined(__x86_64__)
int regs [ 4 ] ;
/* According to http://en.wikipedia.org/wiki/CPUID */
@ -732,10 +1034,50 @@ android_cpuInit(void)
if ( ( regs [ 2 ] & ( 1 < < 23 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_POPCNT ;
}
if ( ( regs [ 2 ] & ( 1 < < 19 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_SSE4_1 ;
}
if ( ( regs [ 2 ] & ( 1 < < 20 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_SSE4_2 ;
}
if ( vendorIsIntel & & ( regs [ 2 ] & ( 1 < < 22 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_MOVBE ;
}
if ( ( regs [ 2 ] & ( 1 < < 25 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_AES_NI ;
}
if ( ( regs [ 2 ] & ( 1 < < 28 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_AVX ;
}
if ( ( regs [ 2 ] & ( 1 < < 30 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_RDRAND ;
}
x86_cpuid ( 7 , regs ) ;
if ( ( regs [ 1 ] & ( 1 < < 5 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_AVX2 ;
}
if ( ( regs [ 1 ] & ( 1 < < 29 ) ) ! = 0 ) {
g_cpuFeatures | = ANDROID_CPU_X86_FEATURE_SHA_NI ;
}
# endif
# if defined( __mips__)
{ /* MIPS and MIPS64 */
/* Extract the list of CPU features from ELF hwcaps */
uint32_t hwcaps = 0 ;
hwcaps = get_elf_hwcap_from_getauxval ( AT_HWCAP ) ;
if ( hwcaps ! = 0 ) {
int has_r6 = ( hwcaps & HWCAP_MIPS_R6 ) ;
int has_msa = ( hwcaps & HWCAP_MIPS_MSA ) ;
if ( has_r6 )
g_cpuFeatures | = ANDROID_CPU_MIPS_FEATURE_R6 ;
if ( has_msa )
g_cpuFeatures | = ANDROID_CPU_MIPS_FEATURE_MSA ;
}
}
# endif /* __mips__ */
free ( cpuinfo ) ;
}
@ -785,6 +1127,25 @@ android_setCpu(int cpu_count, uint64_t cpu_features)
return 1 ;
}
# ifdef __arm__
uint32_t
android_getCpuIdArm ( void )
{
pthread_once ( & g_once , android_cpuInit ) ;
return g_cpuIdArm ;
}
int
android_setCpuArm ( int cpu_count , uint64_t cpu_features , uint32_t cpu_id )
{
if ( ! android_setCpu ( cpu_count , cpu_features ) )
return 0 ;
g_cpuIdArm = cpu_id ;
return 1 ;
}
# endif /* __arm__ */
/*
* Technical note : Making sense of ARM ' s FPU architecture versions .
*