Using android cpufeatures library for detection.
authorArmin Novak <armin.novak@thincast.com>
Tue, 24 Jan 2017 08:56:45 +0000 (09:56 +0100)
committerArmin Novak <armin.novak@thincast.com>
Tue, 24 Jan 2017 08:56:45 +0000 (09:56 +0100)
winpr/libwinpr/sysinfo/CMakeLists.txt
winpr/libwinpr/sysinfo/cpufeatures/Android.mk [new file with mode: 0644]
winpr/libwinpr/sysinfo/cpufeatures/CMakeLists.txt [new file with mode: 0644]
winpr/libwinpr/sysinfo/cpufeatures/NOTICE [new file with mode: 0644]
winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c [new file with mode: 0644]
winpr/libwinpr/sysinfo/cpufeatures/cpu-features.h [new file with mode: 0644]
winpr/libwinpr/sysinfo/cpufeatures/repo.prop [new file with mode: 0644]
winpr/libwinpr/sysinfo/sysinfo.c

index 60592ba..f9b7f69 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+if(ANDROID)
+       add_subdirectory(cpufeatures)
+endif()
+
 winpr_module_add(sysinfo.c)
 
 if((NOT WIN32) AND (NOT APPLE) AND (NOT ANDROID) AND (NOT OPENBSD))
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/Android.mk b/winpr/libwinpr/sysinfo/cpufeatures/Android.mk
new file mode 100644 (file)
index 0000000..7c453fa
--- /dev/null
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+
+ifdef HISTORICAL_NDK_VERSIONS_ROOT
+# This is included by the platform build system.
+include $(CLEAR_VARS)
+LOCAL_MODULE := cpufeatures
+LOCAL_SRC_FILES := cpu-features.c
+LOCAL_SDK_VERSION := 9
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+else # NDK build system
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := cpufeatures
+LOCAL_SRC_FILES := cpu-features.c
+LOCAL_CFLAGS := -Wall -Wextra -Werror
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_EXPORT_LDLIBS := -ldl
+include $(BUILD_STATIC_LIBRARY)
+
+endif # HISTORICAL_NDK_VERSIONS_ROOT
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/CMakeLists.txt b/winpr/libwinpr/sysinfo/cpufeatures/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f1b93df
--- /dev/null
@@ -0,0 +1,20 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-sysinfo cmake build script
+#
+# Copyright 2017 Armin Novak <armin.novak@thincast.com>
+# Copyright 2017 Thincast Technologies GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+winpr_module_add(cpu-features.c cpu-features.h)
+
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/NOTICE b/winpr/libwinpr/sysinfo/cpufeatures/NOTICE
new file mode 100644 (file)
index 0000000..d6c0922
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c b/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c
new file mode 100644 (file)
index 0000000..adff1d7
--- /dev/null
@@ -0,0 +1,1472 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* 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().
+ *
+ * NDK r8c: Add new ARM CPU features: VFPv2, VFP_D32, VFP_FP16,
+ *          VFP_FMA, NEON_FMA, IDIV_ARM, IDIV_THUMB2 and iWMMXt.
+ *
+ *          Rewrite the code to parse /proc/self/auxv instead of
+ *          the "Features" field in /proc/cpuinfo.
+ *
+ *          Dynamically allocate the buffer that hold the content
+ *          of /proc/cpuinfo to deal with newer hardware.
+ *
+ * NDK r7c: Fix CPU count computation. The old method only reported the
+ *           number of _active_ CPUs when the library was initialized,
+ *           which could be less than the real total.
+ *
+ * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7
+ *         for an ARMv6 CPU (see below).
+ *
+ *         Handle kernels that only report 'neon', and not 'vfpv3'
+ *         (VFPv3 is mandated by the ARM architecture is Neon is implemented)
+ *
+ *         Handle kernels that only report 'vfpv3d16', and not 'vfpv3'
+ *
+ *         Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in
+ *         android_getCpuFamily().
+ *
+ * NDK r4: Initial release
+ */
+
+#include "cpu-features.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/system_properties.h>
+#include <unistd.h>
+
+static  pthread_once_t     g_once;
+static  int                g_inited;
+static  AndroidCpuFamily   g_cpuFamily;
+static  uint64_t           g_cpuFeatures;
+static  int                g_cpuCount;
+
+#ifdef __arm__
+static  uint32_t           g_cpuIdArm;
+#endif
+
+static const int android_cpufeatures_debug = 0;
+
+#define  D(...) \
+       do { \
+               if (android_cpufeatures_debug) { \
+                       printf(__VA_ARGS__); fflush(stdout); \
+               } \
+       } while (0)
+
+#ifdef __i386__
+static __inline__ void x86_cpuid(int func, int values[4])
+{
+       int 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 %%ebx\n"
+                            "cpuid\n" \
+                            "mov %%ebx, %1\n"
+                            "pop %%ebx\n"
+                            : "=a"(a), "=r"(b), "=c"(c), "=d"(d) \
+                            : "a"(func) \
+                           );
+       values[0] = a;
+       values[1] = b;
+       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
+ * because files under /proc do not always return a valid size when
+ * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.
+ */
+static int
+get_file_size(const char* pathname)
+{
+       int fd, result = 0;
+       char buffer[256];
+       fd = open(pathname, O_RDONLY);
+
+       if (fd < 0)
+       {
+               D("Can't open %s: %s\n", pathname, strerror(errno));
+               return -1;
+       }
+
+       for (;;)
+       {
+               int ret = read(fd, buffer, sizeof buffer);
+
+               if (ret < 0)
+               {
+                       if (errno == EINTR)
+                               continue;
+
+                       D("Error while reading %s: %s\n", pathname, strerror(errno));
+                       break;
+               }
+
+               if (ret == 0)
+                       break;
+
+               result += ret;
+       }
+
+       close(fd);
+       return result;
+}
+
+/* Read the content of /proc/cpuinfo into a user-provided buffer.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char*  pathname, char*  buffer, size_t  buffsize)
+{
+       int  fd, count;
+       fd = open(pathname, O_RDONLY);
+
+       if (fd < 0)
+       {
+               D("Could not open %s: %s\n", pathname, strerror(errno));
+               return -1;
+       }
+
+       count = 0;
+
+       while (count < (int)buffsize)
+       {
+               int ret = read(fd, buffer + count, buffsize - count);
+
+               if (ret < 0)
+               {
+                       if (errno == EINTR)
+                               continue;
+
+                       D("Error while reading from %s: %s\n", pathname, strerror(errno));
+
+                       if (count == 0)
+                               count = -1;
+
+                       break;
+               }
+
+               if (ret == 0)
+                       break;
+
+               count += ret;
+       }
+
+       close(fd);
+       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.
+ *
+ * Return NULL if not found
+ */
+static char*
+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;
+       const char* p, *q;
+       /* Look for first field occurence, and ensures it starts the line. */
+       p = buffer;
+
+       for (;;)
+       {
+               p = memmem(p, bufend - p, field, fieldlen);
+
+               if (p == NULL)
+                       goto EXIT;
+
+               if (p == buffer || p[-1] == '\n')
+                       break;
+
+               p += fieldlen;
+       }
+
+       /* Skip to the first column followed by a space */
+       p += fieldlen;
+       p  = memchr(p, ':', bufend - p);
+
+       if (p == NULL || p[1] != ' ')
+               goto EXIT;
+
+       /* Find the end of the line */
+       p += 2;
+       q = memchr(p, '\n', bufend - p);
+
+       if (q == NULL)
+               q = bufend;
+
+       /* Copy the line into a heap-allocated buffer */
+       len = q - p;
+       result = malloc(len + 1);
+
+       if (result == NULL)
+               goto EXIT;
+
+       memcpy(result, p, len);
+       result[len] = '\0';
+EXIT:
+       return result;
+}
+
+/* Checks that a space-separated list of items contains one given 'item'.
+ * Returns 1 if found, 0 otherwise.
+ */
+static int
+has_list_item(const char* list, const char* item)
+{
+       const char*  p = list;
+       int itemlen = strlen(item);
+
+       if (list == NULL)
+               return 0;
+
+       while (*p)
+       {
+               const char*  q;
+
+               /* skip spaces */
+               while (*p == ' ' || *p == '\t')
+                       p++;
+
+               /* find end of current list item */
+               q = p;
+
+               while (*q && *q != ' ' && *q != '\t')
+                       q++;
+
+               if (itemlen == q - p && !memcmp(p, item, itemlen))
+                       return 1;
+
+               /* skip to next item */
+               p = q;
+       }
+
+       return 0;
+}
+#endif /* __arm__ */
+
+/* Parse a number 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.
+ * NOTE: Ignores overflows.
+ *
+ * The function returns NULL in case of error (bad format), or the new
+ * position after the decimal number in case of success (which will always
+ * be <= 'limit').
+ */
+static const char*
+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)
+               {
+                       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)
+               return NULL;
+
+       *result = val;
+       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
+ *
+ * For now, we don't expect more than 32 cores on mobile devices, so keep
+ * everything simple.
+ */
+typedef struct
+{
+       uint32_t mask;
+} CpuList;
+
+static __inline__ void
+cpulist_init(CpuList* list)
+{
+       list->mask = 0;
+}
+
+static __inline__ void
+cpulist_and(CpuList* list1, CpuList* list2)
+{
+       list1->mask &= list2->mask;
+}
+
+static __inline__ void
+cpulist_set(CpuList* list, int index)
+{
+       if ((unsigned)index < 32)
+       {
+               list->mask |= (uint32_t)(1U << index);
+       }
+}
+
+static __inline__ int
+cpulist_count(CpuList* list)
+{
+       return __builtin_popcount(list->mask);
+}
+
+/* Parse a textual list of cpus and store the result inside a CpuList object.
+ * Input format is the following:
+ * - comma-separated list of items (no spaces)
+ * - each item is either a single decimal number (cpu index), or a range made
+ *   of two numbers separated by a single dash (-). Ranges are inclusive.
+ *
+ * Examples:   0
+ *             2,4-127,128-143
+ *             0-1
+ */
+static void
+cpulist_parse(CpuList* list, const char* line, int line_len)
+{
+       const char* p = line;
+       const char* end = p + line_len;
+       const char* q;
+
+       /* NOTE: the input line coming from sysfs typically contains a
+        * trailing newline, so take care of it in the code below
+        */
+       while (p < end && *p != '\n')
+       {
+               int val, start_value, end_value;
+               /* Find the end of current item, and put it into 'q' */
+               q = memchr(p, ',', end - p);
+
+               if (q == NULL)
+               {
+                       q = end;
+               }
+
+               /* Get first value */
+               p = parse_decimal(p, q, &start_value);
+
+               if (p == NULL)
+                       goto BAD_FORMAT;
+
+               end_value = start_value;
+
+               /* If we're not at the end of the item, expect a dash and
+                * and integer; extract end value.
+                */
+               if (p < q && *p == '-')
+               {
+                       p = parse_decimal(p + 1, q, &end_value);
+
+                       if (p == NULL)
+                               goto BAD_FORMAT;
+               }
+
+               /* Set bits CPU list bits */
+               for (val = start_value; val <= end_value; val++)
+               {
+                       cpulist_set(list, val);
+               }
+
+               /* Jump to next item */
+               p = q;
+
+               if (p < end)
+                       p++;
+       }
+
+BAD_FORMAT:
+       ;
+}
+
+/* Read a CPU list from one sysfs file */
+static void
+cpulist_read_from(CpuList* list, const char* filename)
+{
+       char   file[64];
+       int    filelen;
+       cpulist_init(list);
+       filelen = read_file(filename, file, sizeof file);
+
+       if (filelen < 0)
+       {
+               D("Could not read %s: %s\n", filename, strerror(errno));
+               return;
+       }
+
+       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)
+#define HWCAP_IWMMXT    (1 << 9)
+#define HWCAP_NEON      (1 << 12)
+#define HWCAP_VFPv3     (1 << 13)
+#define HWCAP_VFPv3D16  (1 << 14)
+#define HWCAP_VFPv4     (1 << 16)
+#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.
+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
+
+#if defined(__arm__)
+// 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_from_proc_self_auxv(void)
+{
+       const char filepath[] = "/proc/self/auxv";
+       int fd = TEMP_FAILURE_RETRY(open(filepath, O_RDONLY));
+
+       if (fd < 0)
+       {
+               D("Could not open %s: %s\n", filepath, strerror(errno));
+               return 0;
+       }
+
+       struct
+       {
+               uint32_t tag;
+               uint32_t value;
+       } entry;
+
+       uint32_t result = 0;
+
+       for (;;)
+       {
+               int ret = TEMP_FAILURE_RETRY(read(fd, (char*)&entry, sizeof entry));
+
+               if (ret < 0)
+               {
+                       D("Error while reading %s: %s\n", filepath, strerror(errno));
+                       break;
+               }
+
+               // Detect end of list.
+               if (ret == 0 || (entry.tag == 0 && entry.value == 0))
+                       break;
+
+               if (entry.tag == AT_HWCAP)
+               {
+                       result = entry.value;
+                       break;
+               }
+       }
+
+       close(fd);
+       return result;
+}
+
+/* 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);
+
+               if (has_list_item(cpuFeatures, "vfp"))
+                       hwcaps |= HWCAP_VFP;
+
+               if (has_list_item(cpuFeatures, "vfpv3"))
+                       hwcaps |= HWCAP_VFPv3;
+
+               if (has_list_item(cpuFeatures, "vfpv3d16"))
+                       hwcaps |= HWCAP_VFPv3D16;
+
+               if (has_list_item(cpuFeatures, "vfpv4"))
+                       hwcaps |= HWCAP_VFPv4;
+
+               if (has_list_item(cpuFeatures, "neon"))
+                       hwcaps |= HWCAP_NEON;
+
+               if (has_list_item(cpuFeatures, "idiva"))
+                       hwcaps |= HWCAP_IDIVA;
+
+               if (has_list_item(cpuFeatures, "idivt"))
+                       hwcaps |= HWCAP_IDIVT;
+
+               if (has_list_item(cpuFeatures, "idiv"))
+                       hwcaps |= HWCAP_IDIVA | HWCAP_IDIVT;
+
+               if (has_list_item(cpuFeatures, "iwmmxt"))
+                       hwcaps |= HWCAP_IWMMXT;
+
+               free(cpuFeatures);
+       }
+
+       return hwcaps;
+}
+#endif  /* __arm__ */
+
+/* Return the number of cpus present on a given device.
+ *
+ * To handle all weird kernel configurations, we need to compute the
+ * intersection of the 'present' and 'possible' CPU lists and count
+ * the result.
+ */
+static int
+get_cpu_count(void)
+{
+       CpuList cpus_present[1];
+       CpuList cpus_possible[1];
+       cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
+       cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
+       /* Compute the intersection of both sets to get the actual number of
+        * CPU cores that can be used on this device by the kernel.
+        */
+       cpulist_and(cpus_present, cpus_possible);
+       return cpulist_count(cpus_present);
+}
+
+static void
+android_cpuInitFamily(void)
+{
+#if defined(__arm__)
+       g_cpuFamily = ANDROID_CPU_FAMILY_ARM;
+#elif defined(__i386__)
+       g_cpuFamily = ANDROID_CPU_FAMILY_X86;
+#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
+}
+
+static void
+android_cpuInit(void)
+{
+       char* cpuinfo = NULL;
+       int   cpuinfo_len;
+       android_cpuInitFamily();
+       g_cpuFeatures = 0;
+       g_cpuCount    = 1;
+       g_inited      = 1;
+       cpuinfo_len = get_file_size("/proc/cpuinfo");
+
+       if (cpuinfo_len < 0)
+       {
+               D("cpuinfo_len cannot be computed!");
+               return;
+       }
+
+       cpuinfo = malloc(cpuinfo_len);
+
+       if (cpuinfo == NULL)
+       {
+               D("cpuinfo buffer could not be allocated");
+               return;
+       }
+
+       cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len);
+       D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len,
+         cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
+
+       if (cpuinfo_len < 0)  /* should not happen */
+       {
+               free(cpuinfo);
+               return;
+       }
+
+       /* Count the CPU cores, the value may be 0 for single-core CPUs */
+       g_cpuCount = get_cpu_count();
+
+       if (g_cpuCount == 0)
+       {
+               g_cpuCount = 1;
+       }
+
+       D("found cpuCount = %d\n", g_cpuCount);
+#ifdef __arm__
+       {
+               /* Extract architecture from the "CPU Architecture" field.
+                * The list is well-known, unlike the the output of
+                * the 'Processor' field which can vary greatly.
+                *
+                * See the definition of the 'proc_arch' array in
+                * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
+                * same file.
+                */
+               char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture");
+
+               if (cpuArch != NULL)
+               {
+                       char*  end;
+                       long   archNumber;
+                       int    hasARMv7 = 0;
+                       D("found cpuArch = '%s'\n", cpuArch);
+                       /* read the initial decimal number, ignore the rest */
+                       archNumber = strtol(cpuArch, &end, 10);
+
+                       /* Note that ARMv8 is upwards compatible with ARMv7. */
+                       if (end > cpuArch && archNumber >= 7)
+                       {
+                               hasARMv7 = 1;
+                       }
+
+                       /* Unfortunately, it seems that certain ARMv6-based CPUs
+                        * report an incorrect architecture number of 7!
+                        *
+                        * See http://code.google.com/p/android/issues/detail?id=10812
+                        *
+                        * We try to correct this by looking at the 'elf_format'
+                        * field reported by the 'Processor' field, which is of the
+                        * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
+                        * an ARMv6-one.
+                        */
+                       if (hasARMv7)
+                       {
+                               char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
+                                                                     "Processor");
+
+                               if (cpuProc != NULL)
+                               {
+                                       D("found cpuProc = '%s'\n", cpuProc);
+
+                                       if (has_list_item(cpuProc, "(v6l)"))
+                                       {
+                                               D("CPU processor and architecture mismatch!!\n");
+                                               hasARMv7 = 0;
+                                       }
+
+                                       free(cpuProc);
+                               }
+                       }
+
+                       if (hasARMv7)
+                       {
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
+                       }
+
+                       /* The LDREX / STREX instructions are available from ARMv6 */
+                       if (archNumber >= 6)
+                       {
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
+                       }
+
+                       free(cpuArch);
+               }
+
+               /* Extract the list of CPU features from ELF hwcaps */
+               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);
+                       int has_vfpv3 = (hwcaps & HWCAP_VFPv3);
+                       int has_vfpv3d16 = (hwcaps & HWCAP_VFPv3D16);
+                       int has_vfpv4 = (hwcaps & HWCAP_VFPv4);
+                       int has_neon = (hwcaps & HWCAP_NEON);
+                       int has_idiva = (hwcaps & HWCAP_IDIVA);
+                       int has_idivt = (hwcaps & HWCAP_IDIVT);
+                       int has_iwmmxt = (hwcaps & HWCAP_IWMMXT);
+
+                       // The kernel does a poor job at ensuring consistency when
+                       // describing CPU features. So lots of guessing is needed.
+
+                       // 'vfpv4' implies VFPv3|VFP_FMA|FP16
+                       if (has_vfpv4)
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3    |
+                                                ANDROID_CPU_ARM_FEATURE_VFP_FP16 |
+                                                ANDROID_CPU_ARM_FEATURE_VFP_FMA;
+
+                       // 'vfpv3' or 'vfpv3d16' imply VFPv3. Note that unlike GCC,
+                       // a value of 'vfpv3' doesn't necessarily mean that the D32
+                       // feature is present, so be conservative. All CPUs in the
+                       // field that support D32 also support NEON, so this should
+                       // not be a problem in practice.
+                       if (has_vfpv3 || has_vfpv3d16)
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+                       // 'vfp' is super ambiguous. Depending on the kernel, it can
+                       // either mean VFPv2 or VFPv3. Make it depend on ARMv7.
+                       if (has_vfp)
+                       {
+                               if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_ARMv7)
+                                       g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+                               else
+                                       g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
+                       }
+
+                       // Neon implies VFPv3|D32, and if vfpv4 is detected, NEON_FMA
+                       if (has_neon)
+                       {
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 |
+                                                ANDROID_CPU_ARM_FEATURE_NEON |
+                                                ANDROID_CPU_ARM_FEATURE_VFP_D32;
+
+                               if (has_vfpv4)
+                                       g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
+                       }
+
+                       // VFPv3 implies VFPv2 and ARMv7
+                       if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_VFPv3)
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2 |
+                                                ANDROID_CPU_ARM_FEATURE_ARMv7;
+
+                       if (has_idiva)
+                               g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
+
+                       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 /* __aarch64__ */
+#if defined(__i386__) || defined(__x86_64__)
+       int regs[4];
+       /* According to http://en.wikipedia.org/wiki/CPUID */
+#define VENDOR_INTEL_b  0x756e6547
+#define VENDOR_INTEL_c  0x6c65746e
+#define VENDOR_INTEL_d  0x49656e69
+       x86_cpuid(0, regs);
+       int vendorIsIntel = (regs[1] == VENDOR_INTEL_b &&
+                            regs[2] == VENDOR_INTEL_c &&
+                            regs[3] == VENDOR_INTEL_d);
+       x86_cpuid(1, regs);
+
+       if ((regs[2] & (1 << 9)) != 0)
+       {
+               g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
+       }
+
+       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);
+}
+
+
+AndroidCpuFamily
+android_getCpuFamily(void)
+{
+       pthread_once(&g_once, android_cpuInit);
+       return g_cpuFamily;
+}
+
+
+uint64_t
+android_getCpuFeatures(void)
+{
+       pthread_once(&g_once, android_cpuInit);
+       return g_cpuFeatures;
+}
+
+
+int
+android_getCpuCount(void)
+{
+       pthread_once(&g_once, android_cpuInit);
+       return g_cpuCount;
+}
+
+static void
+android_cpuInitDummy(void)
+{
+       g_inited = 1;
+}
+
+int
+android_setCpu(int cpu_count, uint64_t cpu_features)
+{
+       /* Fail if the library was already initialized. */
+       if (g_inited)
+               return 0;
+
+       android_cpuInitFamily();
+       g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
+       g_cpuFeatures = cpu_features;
+       pthread_once(&g_once, android_cpuInitDummy);
+       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.
+ *
+ * FPA was ARM's first attempt at an FPU architecture. There is no Android
+ * device that actually uses it since this technology was already obsolete
+ * when the project started. If you see references to FPA instructions
+ * somewhere, you can be sure that this doesn't apply to Android at all.
+ *
+ * FPA was followed by "VFP", soon renamed "VFPv1" due to the emergence of
+ * new versions / additions to it. ARM considers this obsolete right now,
+ * and no known Android device implements it either.
+ *
+ * VFPv2 added a few instructions to VFPv1, and is an *optional* extension
+ * supported by some ARMv5TE, ARMv6 and ARMv6T2 CPUs. Note that a device
+ * supporting the 'armeabi' ABI doesn't necessarily support these.
+ *
+ * VFPv3-D16 adds a few instructions on top of VFPv2 and is typically used
+ * on ARMv7-A CPUs which implement a FPU. Note that it is also mandated
+ * by the Android 'armeabi-v7a' ABI. The -D16 suffix in its name means
+ * that it provides 16 double-precision FPU registers (d0-d15) and 32
+ * single-precision ones (s0-s31) which happen to be mapped to the same
+ * register banks.
+ *
+ * VFPv3-D32 is the name of an extension to VFPv3-D16 that provides 16
+ * additional double precision registers (d16-d31). Note that there are
+ * still only 32 single precision registers.
+ *
+ * VFPv3xD is a *subset* of VFPv3-D16 that only provides single-precision
+ * registers. It is only used on ARMv7-M (i.e. on micro-controllers) which
+ * are not supported by Android. Note that it is not compatible with VFPv2.
+ *
+ * NOTE: The term 'VFPv3' usually designate either VFPv3-D16 or VFPv3-D32
+ *       depending on context. For example GCC uses it for VFPv3-D32, but
+ *       the Linux kernel code uses it for VFPv3-D16 (especially in
+ *       /proc/cpuinfo). Always try to use the full designation when
+ *       possible.
+ *
+ * NEON, a.k.a. "ARM Advanced SIMD" is an extension that provides
+ * instructions to perform parallel computations on vectors of 8, 16,
+ * 32, 64 and 128 bit quantities. NEON requires VFPv32-D32 since all
+ * NEON registers are also mapped to the same register banks.
+ *
+ * VFPv4-D16, adds a few instructions on top of VFPv3-D16 in order to
+ * perform fused multiply-accumulate on VFP registers, as well as
+ * half-precision (16-bit) conversion operations.
+ *
+ * VFPv4-D32 is VFPv4-D16 with 32, instead of 16, FPU double precision
+ * registers.
+ *
+ * VPFv4-NEON is VFPv4-D32 with NEON instructions. It also adds fused
+ * multiply-accumulate instructions that work on the NEON registers.
+ *
+ * NOTE: Similarly, "VFPv4" might either reference VFPv4-D16 or VFPv4-D32
+ *       depending on context.
+ *
+ * The following information was determined by scanning the binutils-2.22
+ * sources:
+ *
+ * Basic VFP instruction subsets:
+ *
+ * #define FPU_VFP_EXT_V1xD 0x08000000     // Base VFP instruction set.
+ * #define FPU_VFP_EXT_V1   0x04000000     // Double-precision insns.
+ * #define FPU_VFP_EXT_V2   0x02000000     // ARM10E VFPr1.
+ * #define FPU_VFP_EXT_V3xD 0x01000000     // VFPv3 single-precision.
+ * #define FPU_VFP_EXT_V3   0x00800000     // VFPv3 double-precision.
+ * #define FPU_NEON_EXT_V1  0x00400000     // Neon (SIMD) insns.
+ * #define FPU_VFP_EXT_D32  0x00200000     // Registers D16-D31.
+ * #define FPU_VFP_EXT_FP16 0x00100000     // Half-precision extensions.
+ * #define FPU_NEON_EXT_FMA 0x00080000     // Neon fused multiply-add
+ * #define FPU_VFP_EXT_FMA  0x00040000     // VFP fused multiply-add
+ *
+ * FPU types (excluding NEON)
+ *
+ * FPU_VFP_V1xD (EXT_V1xD)
+ *    |
+ *    +--------------------------+
+ *    |                          |
+ * FPU_VFP_V1 (+EXT_V1)       FPU_VFP_V3xD (+EXT_V2+EXT_V3xD)
+ *    |                          |
+ *    |                          |
+ * FPU_VFP_V2 (+EXT_V2)       FPU_VFP_V4_SP_D16 (+EXT_FP16+EXT_FMA)
+ *    |
+ * FPU_VFP_V3D16 (+EXT_Vx3D+EXT_V3)
+ *    |
+ *    +--------------------------+
+ *    |                          |
+ * FPU_VFP_V3 (+EXT_D32)     FPU_VFP_V4D16 (+EXT_FP16+EXT_FMA)
+ *    |                          |
+ *    |                      FPU_VFP_V4 (+EXT_D32)
+ *    |
+ * FPU_VFP_HARD (+EXT_FMA+NEON_EXT_FMA)
+ *
+ * VFP architectures:
+ *
+ * ARCH_VFP_V1xD  (EXT_V1xD)
+ *   |
+ *   +------------------+
+ *   |                  |
+ *   |             ARCH_VFP_V3xD (+EXT_V2+EXT_V3xD)
+ *   |                  |
+ *   |             ARCH_VFP_V3xD_FP16 (+EXT_FP16)
+ *   |                  |
+ *   |             ARCH_VFP_V4_SP_D16 (+EXT_FMA)
+ *   |
+ * ARCH_VFP_V1 (+EXT_V1)
+ *   |
+ * ARCH_VFP_V2 (+EXT_V2)
+ *   |
+ * ARCH_VFP_V3D16 (+EXT_V3xD+EXT_V3)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V3D16_FP16  (+EXT_FP16)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA)
+ *   |                   |
+ *   |         ARCH_VFP_V4 (+EXT_D32)
+ *   |                   |
+ *   |         ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA)
+ *   |
+ * ARCH_VFP_V3 (+EXT_D32)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V3_FP16 (+EXT_FP16)
+ *   |
+ * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON)
+ *   |
+ * ARCH_NEON_FP16 (+EXT_FP16)
+ *
+ * -fpu=<name> values and their correspondance with FPU architectures above:
+ *
+ *   {"vfp",               FPU_ARCH_VFP_V2},
+ *   {"vfp9",              FPU_ARCH_VFP_V2},
+ *   {"vfp3",              FPU_ARCH_VFP_V3}, // For backwards compatbility.
+ *   {"vfp10",             FPU_ARCH_VFP_V2},
+ *   {"vfp10-r0",          FPU_ARCH_VFP_V1},
+ *   {"vfpxd",             FPU_ARCH_VFP_V1xD},
+ *   {"vfpv2",             FPU_ARCH_VFP_V2},
+ *   {"vfpv3",             FPU_ARCH_VFP_V3},
+ *   {"vfpv3-fp16",        FPU_ARCH_VFP_V3_FP16},
+ *   {"vfpv3-d16",         FPU_ARCH_VFP_V3D16},
+ *   {"vfpv3-d16-fp16",    FPU_ARCH_VFP_V3D16_FP16},
+ *   {"vfpv3xd",           FPU_ARCH_VFP_V3xD},
+ *   {"vfpv3xd-fp16",      FPU_ARCH_VFP_V3xD_FP16},
+ *   {"neon",              FPU_ARCH_VFP_V3_PLUS_NEON_V1},
+ *   {"neon-fp16",         FPU_ARCH_NEON_FP16},
+ *   {"vfpv4",             FPU_ARCH_VFP_V4},
+ *   {"vfpv4-d16",         FPU_ARCH_VFP_V4D16},
+ *   {"fpv4-sp-d16",       FPU_ARCH_VFP_V4_SP_D16},
+ *   {"neon-vfpv4",        FPU_ARCH_NEON_VFP_V4},
+ *
+ *
+ * Simplified diagram that only includes FPUs supported by Android:
+ * Only ARCH_VFP_V3D16 is actually mandated by the armeabi-v7a ABI,
+ * all others are optional and must be probed at runtime.
+ *
+ * ARCH_VFP_V3D16 (EXT_V1xD+EXT_V1+EXT_V2+EXT_V3xD+EXT_V3)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V3D16_FP16  (+EXT_FP16)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA)
+ *   |                   |
+ *   |         ARCH_VFP_V4 (+EXT_D32)
+ *   |                   |
+ *   |         ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA)
+ *   |
+ * ARCH_VFP_V3 (+EXT_D32)
+ *   |
+ *   +-------------------+
+ *   |                   |
+ *   |         ARCH_VFP_V3_FP16 (+EXT_FP16)
+ *   |
+ * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON)
+ *   |
+ * ARCH_NEON_FP16 (+EXT_FP16)
+ *
+ */
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.h b/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.h
new file mode 100644 (file)
index 0000000..e95ed9d
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef CPU_FEATURES_H
+#define CPU_FEATURES_H
+
+#include <sys/cdefs.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+/* A list of valid values returned by android_getCpuFamily().
+ * They describe the CPU Architecture of the current process.
+ */
+typedef enum
+{
+       ANDROID_CPU_FAMILY_UNKNOWN = 0,
+       ANDROID_CPU_FAMILY_ARM,
+       ANDROID_CPU_FAMILY_X86,
+       ANDROID_CPU_FAMILY_MIPS,
+       ANDROID_CPU_FAMILY_ARM64,
+       ANDROID_CPU_FAMILY_X86_64,
+       ANDROID_CPU_FAMILY_MIPS64,
+
+       ANDROID_CPU_FAMILY_MAX  /* do not remove */
+
+} AndroidCpuFamily;
+
+/* Return the CPU family of the current process.
+ *
+ * Note that this matches the bitness of the current process. I.e. when
+ * running a 32-bit binary on a 64-bit capable CPU, this will return the
+ * 32-bit CPU family value.
+ */
+extern AndroidCpuFamily android_getCpuFamily(void);
+
+/* Return a bitmap describing a set of optional CPU features that are
+ * supported by the current device's CPU. The exact bit-flags returned
+ * depend on the value returned by android_getCpuFamily(). See the
+ * documentation for the ANDROID_CPU_*_FEATURE_* flags below for details.
+ */
+extern uint64_t android_getCpuFeatures(void);
+
+/* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be
+ * recognized by the library (see note below for 64-bit ARM). Value details
+ * are:
+ *
+ *   VFPv2:
+ *     CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs
+ *     support these instructions. VFPv2 is a subset of VFPv3 so this will
+ *     be set whenever VFPv3 is set too.
+ *
+ *   ARMv7:
+ *     CPU supports the ARMv7-A basic instruction set.
+ *     This feature is mandated by the 'armeabi-v7a' ABI.
+ *
+ *   VFPv3:
+ *     CPU supports the VFPv3-D16 instruction set, providing hardware FPU
+ *     support for single and double precision floating point registers.
+ *     Note that only 16 FPU registers are available by default, unless
+ *     the D32 bit is set too. This feature is also mandated by the
+ *     'armeabi-v7a' ABI.
+ *
+ *   VFP_D32:
+ *     CPU VFP optional extension that provides 32 FPU registers,
+ *     instead of 16. Note that ARM mandates this feature is the 'NEON'
+ *     feature is implemented by the CPU.
+ *
+ *   NEON:
+ *     CPU FPU supports "ARM Advanced SIMD" instructions, also known as
+ *     NEON. Note that this mandates the VFP_D32 feature as well, per the
+ *     ARM Architecture specification.
+ *
+ *   VFP_FP16:
+ *     Half-width floating precision VFP extension. If set, the CPU
+ *     supports instructions to perform floating-point operations on
+ *     16-bit registers. This is part of the VFPv4 specification, but
+ *     not mandated by any Android ABI.
+ *
+ *   VFP_FMA:
+ *     Fused multiply-accumulate VFP instructions extension. Also part of
+ *     the VFPv4 specification, but not mandated by any Android ABI.
+ *
+ *   NEON_FMA:
+ *     Fused multiply-accumulate NEON instructions extension. Optional
+ *     extension from the VFPv4 specification, but not mandated by any
+ *     Android ABI.
+ *
+ *   IDIV_ARM:
+ *     Integer division available in ARM mode. Only available
+ *     on recent CPUs (e.g. Cortex-A15).
+ *
+ *   IDIV_THUMB2:
+ *     Integer division available in Thumb-2 mode. Only available
+ *     on recent CPUs (e.g. Cortex-A15).
+ *
+ *   iWMMXt:
+ *     Optional extension that adds MMX registers and operations to an
+ *     ARM CPU. This is only available on a few XScale-based CPU designs
+ *     sold by Marvell. Pretty rare in practice.
+ *
+ *   AES:
+ *     CPU supports AES instructions. These instructions are only
+ *     available for 32-bit applications running on ARMv8 CPU.
+ *
+ *   CRC32:
+ *     CPU supports CRC32 instructions. These instructions are only
+ *     available for 32-bit applications running on ARMv8 CPU.
+ *
+ *   SHA2:
+ *     CPU supports SHA2 instructions. These instructions are only
+ *     available for 32-bit applications running on ARMv8 CPU.
+ *
+ *   SHA1:
+ *     CPU supports SHA1 instructions. These instructions are only
+ *     available for 32-bit applications running on ARMv8 CPU.
+ *
+ *   PMULL:
+ *     CPU supports 64-bit PMULL and PMULL2 instructions. These
+ *     instructions are only available for 32-bit applications
+ *     running on ARMv8 CPU.
+ *
+ * If you want to tell the compiler to generate code that targets one of
+ * the feature set above, you should probably use one of the following
+ * flags (for more details, see technical note at the end of this file):
+ *
+ *   -mfpu=vfp
+ *   -mfpu=vfpv2
+ *     These are equivalent and tell GCC to use VFPv2 instructions for
+ *     floating-point operations. Use this if you want your code to
+ *     run on *some* ARMv6 devices, and any ARMv7-A device supported
+ *     by Android.
+ *
+ *     Generated code requires VFPv2 feature.
+ *
+ *   -mfpu=vfpv3-d16
+ *     Tell GCC to use VFPv3 instructions (using only 16 FPU registers).
+ *     This should be generic code that runs on any CPU that supports the
+ *     'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this.
+ *
+ *     Generated code requires VFPv3 feature.
+ *
+ *   -mfpu=vfpv3
+ *     Tell GCC to use VFPv3 instructions with 32 FPU registers.
+ *     Generated code requires VFPv3|VFP_D32 features.
+ *
+ *   -mfpu=neon
+ *     Tell GCC to use VFPv3 instructions with 32 FPU registers, and
+ *     also support NEON intrinsics (see <arm_neon.h>).
+ *     Generated code requires VFPv3|VFP_D32|NEON features.
+ *
+ *   -mfpu=vfpv4-d16
+ *     Generated code requires VFPv3|VFP_FP16|VFP_FMA features.
+ *
+ *   -mfpu=vfpv4
+ *     Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features.
+ *
+ *   -mfpu=neon-vfpv4
+ *     Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA
+ *     features.
+ *
+ *   -mcpu=cortex-a7
+ *   -mcpu=cortex-a15
+ *     Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|
+ *                             NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2
+ *     This flag implies -mfpu=neon-vfpv4.
+ *
+ *   -mcpu=iwmmxt
+ *     Allows the use of iWMMXt instrinsics with GCC.
+ *
+ * IMPORTANT NOTE: These flags should only be tested when
+ * android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a
+ * 32-bit process.
+ *
+ * When running a 64-bit ARM process on an ARMv8 CPU,
+ * android_getCpuFeatures() will return a different set of bitflags
+ */
+enum
+{
+       ANDROID_CPU_ARM_FEATURE_ARMv7       = (1 << 0),
+       ANDROID_CPU_ARM_FEATURE_VFPv3       = (1 << 1),
+       ANDROID_CPU_ARM_FEATURE_NEON        = (1 << 2),
+       ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
+       ANDROID_CPU_ARM_FEATURE_VFPv2       = (1 << 4),
+       ANDROID_CPU_ARM_FEATURE_VFP_D32     = (1 << 5),
+       ANDROID_CPU_ARM_FEATURE_VFP_FP16    = (1 << 6),
+       ANDROID_CPU_ARM_FEATURE_VFP_FMA     = (1 << 7),
+       ANDROID_CPU_ARM_FEATURE_NEON_FMA    = (1 << 8),
+       ANDROID_CPU_ARM_FEATURE_IDIV_ARM    = (1 << 9),
+       ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10),
+       ANDROID_CPU_ARM_FEATURE_iWMMXt      = (1 << 11),
+       ANDROID_CPU_ARM_FEATURE_AES         = (1 << 12),
+       ANDROID_CPU_ARM_FEATURE_PMULL       = (1 << 13),
+       ANDROID_CPU_ARM_FEATURE_SHA1        = (1 << 14),
+       ANDROID_CPU_ARM_FEATURE_SHA2        = (1 << 15),
+       ANDROID_CPU_ARM_FEATURE_CRC32       = (1 << 16),
+};
+
+/* The bit flags corresponding to the output of android_getCpuFeatures()
+ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details
+ * are:
+ *
+ *   FP:
+ *     CPU has Floating-point unit.
+ *
+ *   ASIMD:
+ *     CPU has Advanced SIMD unit.
+ *
+ *   AES:
+ *     CPU supports AES instructions.
+ *
+ *   CRC32:
+ *     CPU supports CRC32 instructions.
+ *
+ *   SHA2:
+ *     CPU supports SHA2 instructions.
+ *
+ *   SHA1:
+ *     CPU supports SHA1 instructions.
+ *
+ *   PMULL:
+ *     CPU supports 64-bit PMULL and PMULL2 instructions.
+ */
+enum
+{
+       ANDROID_CPU_ARM64_FEATURE_FP      = (1 << 0),
+       ANDROID_CPU_ARM64_FEATURE_ASIMD   = (1 << 1),
+       ANDROID_CPU_ARM64_FEATURE_AES     = (1 << 2),
+       ANDROID_CPU_ARM64_FEATURE_PMULL   = (1 << 3),
+       ANDROID_CPU_ARM64_FEATURE_SHA1    = (1 << 4),
+       ANDROID_CPU_ARM64_FEATURE_SHA2    = (1 << 5),
+       ANDROID_CPU_ARM64_FEATURE_CRC32   = (1 << 6),
+};
+
+/* The bit flags corresponding to the output of android_getCpuFeatures()
+ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or
+ * ANDROID_CPU_FAMILY_X86_64.
+ */
+enum
+{
+       ANDROID_CPU_X86_FEATURE_SSSE3  = (1 << 0),
+       ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
+       ANDROID_CPU_X86_FEATURE_MOVBE  = (1 << 2),
+       ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3),
+       ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4),
+       ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5),
+       ANDROID_CPU_X86_FEATURE_AVX = (1 << 6),
+       ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7),
+       ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8),
+       ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9),
+};
+
+/* The bit flags corresponding to the output of android_getCpuFeatures()
+ * when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS
+ * or ANDROID_CPU_FAMILY_MIPS64.  Values are:
+ *
+ *   R6:
+ *     CPU executes MIPS Release 6 instructions natively, and
+ *     supports obsoleted R1..R5 instructions only via kernel traps.
+ *
+ *   MSA:
+ *     CPU supports Mips SIMD Architecture instructions.
+ */
+enum
+{
+       ANDROID_CPU_MIPS_FEATURE_R6    = (1 << 0),
+       ANDROID_CPU_MIPS_FEATURE_MSA   = (1 << 1),
+};
+
+
+/* Return the number of CPU cores detected on this device. */
+extern int android_getCpuCount(void);
+
+/* The following is used to force the CPU count and features
+ * mask in sandboxed processes. Under 4.1 and higher, these processes
+ * cannot access /proc, which is the only way to get information from
+ * the kernel about the current hardware (at least on ARM).
+ *
+ * It _must_ be called only once, and before any android_getCpuXXX
+ * function, any other case will fail.
+ *
+ * This function return 1 on success, and 0 on failure.
+ */
+extern int android_setCpu(int      cpu_count,
+                          uint64_t cpu_features);
+
+#ifdef __arm__
+/* Retrieve the ARM 32-bit CPUID value from the kernel.
+ * Note that this cannot work on sandboxed processes under 4.1 and
+ * higher, unless you called android_setCpuArm() before.
+ */
+extern uint32_t android_getCpuIdArm(void);
+
+/* An ARM-specific variant of android_setCpu() that also allows you
+ * to set the ARM CPUID field.
+ */
+extern int android_setCpuArm(int      cpu_count,
+                             uint64_t cpu_features,
+                             uint32_t cpu_id);
+#endif
+
+__END_DECLS
+
+#endif /* CPU_FEATURES_H */
diff --git a/winpr/libwinpr/sysinfo/cpufeatures/repo.prop b/winpr/libwinpr/sysinfo/cpufeatures/repo.prop
new file mode 100644 (file)
index 0000000..76190f4
--- /dev/null
@@ -0,0 +1,55 @@
+platform/bionic ed9e6a41c92c9552be84ecc126e29b4604eee246
+platform/development 33b95fc1d131d4b07a67d14dce776217f4c36d9a
+platform/external/googletest 013ee6fccb6bb9ebd6215b504f0eef45dccfde4e
+platform/external/libcxx 45e09a55b249d0d97942702c26850e4b3c424b92
+platform/external/libcxxabi 9711d72e91f48830db3f4e8133d1e2e328e8504c
+platform/external/libunwind_llvm fecc6f26cfdbfc9cf0ea2021629ac6e85b7c0113
+platform/external/llvm c62dc90488ad1807fab24cb56f98fb88585c08a2
+platform/external/shaderc/glslang 59ebccccee399c0577230aeb608259fa71d7b1b7
+platform/external/shaderc/shaderc fcd85bc9ec80390d39d204360d2c36a6423146f0
+platform/external/shaderc/spirv-headers 9bec171dc9ffda91c2291102c04d75b10bf01e8a
+platform/external/shaderc/spirv-tools 410cd1fca9703990880d4ddc53bb0b367889b173
+platform/external/vulkan-validation-layers cbc75f522adb1f0cc3d86caae467faccce840b04
+platform/manifest c421db3ebcf25f0642b4032118d4a2754f6f457c
+platform/ndk d982fe4778a3d7d00c4df53502d630c808f025a3
+platform/prebuilts/clang/host/darwin-x86 e60e8d81fb820b988728ea5b2ab6c8f34bc2d978
+platform/prebuilts/clang/host/linux-x86 860bed8090d2d47e5646b34ef2ed7e756d222bc4
+platform/prebuilts/clang/host/windows-x86 90efd850fcd95bfdd9945e4c0e90e4cb396d2a6c
+platform/prebuilts/cmake/darwin-x86 289589930105f9db21313bfd5aaa4a5fe02509e5
+platform/prebuilts/cmake/linux-x86 ee96b2ec399702e23faee15863fed3ae33144fdd
+platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9 51fa77f10f8c5ee658bfaf3e5a2a29ebd8de50d2
+platform/prebuilts/gcc/darwin-x86/arm/arm-eabi-4.8 6d08ca9f45ff685648fd13c75bf5cac4b11c19bb
+platform/prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9 39fd9577fe3895a68a921216836ebdd46b4255a8
+platform/prebuilts/gcc/darwin-x86/host/headers 4ac4f7cc41cf3c9e36fc3d6cf37fd1cfa9587a68
+platform/prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1 ec5aa66aaa4964c27564d0ec84dc1f18a2d72b7e
+platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9 4ba48d4ace63404304f201dc7d5e87ac55fc7d59
+platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9 2500bd9aaa640c179730df7f7315d5ee90e4c3c1
+platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 423c0265176bcabd1c885f8cf6f0cedf67d3f59b
+platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8 26e93f6af47f7bd3a9beb5c102a5f45e19bfa38a
+platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9 887574f98e97475d6fb2f91a8f7b24602466017a
+platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8 1273431a189717842f033573eb8c777e13dd88b7
+platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8 73ca99196723f810dad42390d154654354f57c16
+platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8 c795eed743bc6cee4ead5407cc237c43abf6fa26
+platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9 88bfecab5b700a1f6a601434d5816fab6c9261fc
+platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9 e3b93a8f44d43101b396d41ef30562885714e130
+platform/prebuilts/ndk adc9927c0f3f5107a777a67b94a4b1f447255681
+platform/prebuilts/ninja/darwin-x86 cc147ae2956e96279085abfadda2767b50edc2cc
+platform/prebuilts/ninja/linux-x86 543112c6744acb7a018ac36118eb2a862834809b
+platform/prebuilts/python/darwin-x86/2.7.5 0c5958b1636c47ed7c284f859c8e805fd06a0e63
+platform/prebuilts/python/linux-x86/2.7.5 ce294655f981e19b420f2201b7c499a435ef1ce2
+platform/prebuilts/simpleperf 7323ef4840428a32b6e9d8b58fcce87e05295b05
+toolchain/binutils 6422a80df992e4542dbd4fb70a04f316065674af
+toolchain/build f280657461aee54b6d2807881d8a77832f4e794c
+toolchain/cloog 604793eab97d360aef729f064674569ee6dbf3e1
+toolchain/expat 40172a0ae9d40a068f1e1a48ffcf6a1ccf765ed5
+toolchain/gcc 535de7eb0179bdcd01fcd99f1dad6208250d3706
+toolchain/gdb b66267cc5491513a9ad0369761a1c1b52bf15fed
+toolchain/gmp b2acd5dbf47868ac5b5bc844e16d2cadcbd4c810
+toolchain/isl 0ccf95726af8ce58ad61ff474addbce3a31ba99c
+toolchain/mpc 835d16e92eed875638a8b5d552034c3b1aae045b
+toolchain/mpfr de979fc377db766591e7feaf052f0de59be46e76
+toolchain/ppl 979062d362bc5a1c00804237b408b19b4618fb24
+toolchain/python 6a7fc9bfd21da85dda97a8bcd2952e0bfbded424
+toolchain/sed 45df23d6dc8b51ea5cd903d023c10fd7d72415b9
+toolchain/xz 595407f5a237e9bfd6821d70096d38825ec9c4e0
+toolchain/yasm a159fe073809b4138cf90b7298ea31ea17af85c0
index b00ad3f..27e9c57 100644 (file)
 #include <winpr/sysinfo.h>
 #include <winpr/platform.h>
 
-#if defined(__linux__) && defined(__GNUC__)
+#if defined(ANDROID)
+#include "cpufeatures/cpu-features.h"
+#endif
+
+#if defined(__linux__)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -75,7 +79,34 @@ defined(__OpenBSD__) || defined(__DragonFly__)
 static DWORD GetProcessorArchitecture(void)
 {
        DWORD cpuArch = PROCESSOR_ARCHITECTURE_UNKNOWN;
-#if defined(_M_ARM)
+#if defined(ANDROID)
+       AndroidCpuFamily family = android_getCpuFamily();
+
+       switch (family)
+       {
+           case ANDROID_CPU_FAMILY_ARM:
+                   return PROCESSOR_ARCHITECTURE_ARM;
+
+           case ANDROID_CPU_FAMILY_X86:
+                   return PROCESSOR_ARCHITECTURE_INTEL;
+
+           case ANDROID_CPU_FAMILY_MIPS:
+                   return PROCESSOR_ARCHITECTURE_MIPS;
+
+           case ANDROID_CPU_FAMILY_ARM64:
+                   return PROCESSOR_ARCHITECTURE_ARM64;
+
+           case ANDROID_CPU_FAMILY_X86_64:
+                   return PROCESSOR_ARCHITECTURE_AMD64;
+
+           case ANDROID_CPU_FAMILY_MIPS64:
+                   return PROCESSOR_ARCHITECTURE_MIPS64;
+
+           default:
+                   return PROCESSOR_ARCHITECTURE_UNKNOWN;
+       }
+
+#elif defined(_M_ARM)
        cpuArch = PROCESSOR_ARCHITECTURE_ARM;
 #elif defined(_M_IX86)
        cpuArch = PROCESSOR_ARCHITECTURE_INTEL;
@@ -99,8 +130,10 @@ static DWORD GetProcessorArchitecture(void)
 static DWORD GetNumberOfProcessors(void)
 {
        DWORD numCPUs = 1;
+#if defined(ANDROID)
+       return android_getCpuCount();
        /* TODO: iOS */
-#if defined(__linux__) || defined(__sun) || defined(_AIX)
+#elif defined(__linux__) || defined(__sun) || defined(_AIX)
        numCPUs = (DWORD) sysconf(_SC_NPROCESSORS_ONLN);
 #elif defined(__MACOSX__) || \
        defined(__FreeBSD__) || defined(__NetBSD__) || \
@@ -204,6 +237,7 @@ void GetSystemTime(LPSYSTEMTIME lpSystemTime)
 
 BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime)
 {
+       /* TODO: Implement */
        return FALSE;
 }
 
@@ -232,6 +266,7 @@ VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
 
 BOOL SetLocalTime(CONST SYSTEMTIME* lpSystemTime)
 {
+       /* TODO: Implement */
        return FALSE;
 }
 
@@ -249,6 +284,7 @@ VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
 BOOL GetSystemTimeAdjustment(PDWORD lpTimeAdjustment, PDWORD lpTimeIncrement,
                              PBOOL lpTimeAdjustmentDisabled)
 {
+       /* TODO: Implement */
        return FALSE;
 }
 
@@ -398,13 +434,13 @@ BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD l
 
        switch (NameType)
        {
-               case ComputerNameDnsHostname:
-               case ComputerNameDnsDomain:
-               case ComputerNameDnsFullyQualified:
-               case ComputerNamePhysicalDnsHostname:
-               case ComputerNamePhysicalDnsDomain:
-               case ComputerNamePhysicalDnsFullyQualified:
-                       if (*lpnSize <= (DWORD) length)
+           case ComputerNameDnsHostname:
+           case ComputerNameDnsDomain:
+           case ComputerNameDnsFullyQualified:
+           case ComputerNamePhysicalDnsHostname:
+           case ComputerNamePhysicalDnsDomain:
+           case ComputerNamePhysicalDnsFullyQualified:
+                   if (*lpnSize <= (DWORD) length)
                        {
                                *lpnSize = length + 1;
                                SetLastError(ERROR_MORE_DATA);
@@ -416,10 +452,10 @@ BOOL GetComputerNameExA(COMPUTER_NAME_FORMAT NameType, LPSTR lpBuffer, LPDWORD l
 
                        CopyMemory(lpBuffer, hostname, length);
                        lpBuffer[length] = '\0';
-                       break;
+                   break;
 
-               default:
-                       return FALSE;
+           default:
+                   return FALSE;
        }
 
        return TRUE;
@@ -512,8 +548,8 @@ static void cpuid(
        __asm volatile
        (
            /* The EBX (or RBX register on x86_64) is used for the PIC base address
-            * and must not be corrupted by our inline assembly.
-            */
+                * and must not be corrupted by our inline assembly.
+                */
 #ifdef _M_IX86
            "mov %%ebx, %%esi;"
            "cpuid;"
@@ -603,85 +639,98 @@ static unsigned GetARMCPUCaps(void)
 BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
 {
        BOOL ret = FALSE;
-#ifdef _M_ARM
+#if defined(ANDROID)
+       const uint64_t features = android_getCpuFeatures();
+
+       switch (ProcessorFeature)
+       {
+           case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
+           case PF_ARM_NEON:
+                   return features & ANDROID_CPU_ARM_FEATURE_NEON;
+
+           default:
+                   return FALSE;
+       }
+
+#elif defined(_M_ARM)
 #ifdef __linux__
        const unsigned caps = GetARMCPUCaps();
 
        switch (ProcessorFeature)
        {
-               case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
-               case PF_ARM_NEON:
-                       if (caps & HWCAP_NEON)
+           case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
+           case PF_ARM_NEON:
+                   if (caps & HWCAP_NEON)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_THUMB:
-                       if (caps & HWCAP_THUMB)
+           case PF_ARM_THUMB:
+                   if (caps & HWCAP_THUMB)
                                ret = TRUE;
 
-               case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
-                       if (caps & HWCAP_VFPD32)
+           case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
+                   if (caps & HWCAP_VFPD32)
                                ret = TRUE;
 
-               case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
-                       if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
+           case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
+                   if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
                                ret = TRUE;
 
-               case PF_ARM_VFP3:
-                       if (caps & HWCAP_VFPv3)
+           case PF_ARM_VFP3:
+                   if (caps & HWCAP_VFPv3)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_JAZELLE:
-                       if (caps & HWCAP_JAVA)
+           case PF_ARM_JAZELLE:
+                   if (caps & HWCAP_JAVA)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_DSP:
-                       if (caps & HWCAP_EDSP)
+           case PF_ARM_DSP:
+                   if (caps & HWCAP_EDSP)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_MPU:
-                       if (caps & HWCAP_EDSP)
+           case PF_ARM_MPU:
+                   if (caps & HWCAP_EDSP)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_THUMB2:
-                       if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
+           case PF_ARM_THUMB2:
+                   if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_T2EE:
-                       if (caps & HWCAP_THUMBEE)
+           case PF_ARM_T2EE:
+                   if (caps & HWCAP_THUMBEE)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_ARM_INTEL_WMMX:
-                       if (caps & HWCAP_IWMMXT)
+           case PF_ARM_INTEL_WMMX:
+                   if (caps & HWCAP_IWMMXT)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               default:
-                       break;
+           default:
+                   break;
        }
 
 #elif defined(__APPLE__) // __linux__
 
        switch (ProcessorFeature)
        {
-               case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
-               case PF_ARM_NEON:
-                       ret = TRUE;
-                       break;
+           case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
+           case PF_ARM_NEON:
+                   ret = TRUE;
+                   break;
        }
 
 #endif // __linux__
@@ -692,38 +741,38 @@ BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
 
        switch (ProcessorFeature)
        {
-               case PF_MMX_INSTRUCTIONS_AVAILABLE:
-                       if (d & D_BIT_MMX)
+           case PF_MMX_INSTRUCTIONS_AVAILABLE:
+                   if (d & D_BIT_MMX)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_XMMI_INSTRUCTIONS_AVAILABLE:
-                       if (d & D_BIT_SSE)
+           case PF_XMMI_INSTRUCTIONS_AVAILABLE:
+                   if (d & D_BIT_SSE)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
-                       if (d & D_BIT_SSE2)
+           case PF_XMMI64_INSTRUCTIONS_AVAILABLE:
+                   if (d & D_BIT_SSE2)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
-                       if (d & D_BIT_3DN)
+           case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
+                   if (d & D_BIT_3DN)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_SSE3_INSTRUCTIONS_AVAILABLE:
-                       if (c & C_BIT_SSE3)
+           case PF_SSE3_INSTRUCTIONS_AVAILABLE:
+                   if (c & C_BIT_SSE3)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               default:
-                       break;
+           default:
+                   break;
        }
 
 #endif // __GNUC__
@@ -756,35 +805,35 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
 
        switch (ProcessorFeature)
        {
-               case PF_EX_ARM_VFP1:
-                       if (caps & HWCAP_VFP)
+           case PF_EX_ARM_VFP1:
+                   if (caps & HWCAP_VFP)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_ARM_VFP3D16:
-                       if (caps & HWCAP_VFPv3D16)
+           case PF_EX_ARM_VFP3D16:
+                   if (caps & HWCAP_VFPv3D16)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_ARM_VFP4:
-                       if (caps & HWCAP_VFPv4)
+           case PF_EX_ARM_VFP4:
+                   if (caps & HWCAP_VFPv4)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_ARM_IDIVA:
-                       if (caps & HWCAP_IDIVA)
+           case PF_EX_ARM_IDIVA:
+                   if (caps & HWCAP_IDIVA)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_ARM_IDIVT:
-                       if (caps & HWCAP_IDIVT)
+           case PF_EX_ARM_IDIVT:
+                   if (caps & HWCAP_IDIVT)
                                ret = TRUE;
 
-                       break;
+                   break;
        }
 
 #endif // __linux__
@@ -794,48 +843,48 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
 
        switch (ProcessorFeature)
        {
-               case PF_EX_LZCNT:
-                       {
-                               unsigned a81, b81, c81, d81;
+           case PF_EX_LZCNT:
+               {
+                       unsigned a81, b81, c81, d81;
                                cpuid(0x80000001, &a81, &b81, &c81, &d81);
 
                                if (c81 & C81_BIT_LZCNT)
                                        ret = TRUE;
-                       }
-                       break;
+               }
+                   break;
 
-               case PF_EX_3DNOW_PREFETCH:
-                       if (c & C_BIT_3DNP)
+           case PF_EX_3DNOW_PREFETCH:
+                   if (c & C_BIT_3DNP)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_SSSE3:
-                       if (c & C_BIT_SSSE3)
+           case PF_EX_SSSE3:
+                   if (c & C_BIT_SSSE3)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_SSE41:
-                       if (c & C_BIT_SSE41)
+           case PF_EX_SSE41:
+                   if (c & C_BIT_SSE41)
                                ret = TRUE;
 
-                       break;
+                   break;
 
-               case PF_EX_SSE42:
-                       if (c & C_BIT_SSE42)
+           case PF_EX_SSE42:
+                   if (c & C_BIT_SSE42)
                                ret = TRUE;
 
-                       break;
+                   break;
 #if defined(__GNUC__) && defined(__AVX__)
 
-               case PF_EX_AVX:
-               case PF_EX_FMA:
-               case PF_EX_AVX_AES:
-               case PF_EX_AVX_PCLMULQDQ:
-                       {
-                               /* Check for general AVX support */
-                               if ((c & C_BITS_AVX) != C_BITS_AVX)
+           case PF_EX_AVX:
+           case PF_EX_FMA:
+           case PF_EX_AVX_AES:
+           case PF_EX_AVX_PCLMULQDQ:
+               {
+                       /* Check for general AVX support */
+                       if ((c & C_BITS_AVX) != C_BITS_AVX)
                                        break;
 
                                int e, f;
@@ -846,35 +895,35 @@ BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
                                {
                                        switch (ProcessorFeature)
                                        {
-                                               case PF_EX_AVX:
-                                                       ret = TRUE;
-                                                       break;
+                                           case PF_EX_AVX:
+                                                   ret = TRUE;
+                                                   break;
 
-                                               case PF_EX_FMA:
-                                                       if (c & C_BIT_FMA)
+                                           case PF_EX_FMA:
+                                                   if (c & C_BIT_FMA)
                                                                ret = TRUE;
 
-                                                       break;
+                                                   break;
 
-                                               case PF_EX_AVX_AES:
-                                                       if (c & C_BIT_AES)
+                                           case PF_EX_AVX_AES:
+                                                   if (c & C_BIT_AES)
                                                                ret = TRUE;
 
-                                                       break;
+                                                   break;
 
-                                               case PF_EX_AVX_PCLMULQDQ:
-                                                       if (c & C_BIT_PCLMULQDQ)
+                                           case PF_EX_AVX_PCLMULQDQ:
+                                                   if (c & C_BIT_PCLMULQDQ)
                                                                ret = TRUE;
 
-                                                       break;
+                                                   break;
                                        }
                                }
-                       }
-                       break;
+               }
+                   break;
 #endif //__AVX__
 
-               default:
-                       break;
+           default:
+                   break;
        }
 
 #endif