File size: 3,709 Bytes
8b7c501 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dlfcn.h>
#include <elf.h>
#if CPUINFO_MOCK
#include <cpuinfo-mock.h>
#endif
#include <cpuinfo.h>
#include <arm/linux/api.h>
#include <cpuinfo/log.h>
#if CPUINFO_ARCH_ARM64 || CPUINFO_ARCH_ARM && !defined(__ANDROID__)
#include <sys/auxv.h>
#else
#define AT_HWCAP 16
#define AT_HWCAP2 26
#endif
#if CPUINFO_MOCK
static uint32_t mock_hwcap = 0;
void cpuinfo_set_hwcap(uint32_t hwcap) {
mock_hwcap = hwcap;
}
static uint32_t mock_hwcap2 = 0;
void cpuinfo_set_hwcap2(uint32_t hwcap2) {
mock_hwcap2 = hwcap2;
}
#endif
#if CPUINFO_ARCH_ARM
typedef unsigned long (*getauxval_function_t)(unsigned long);
bool cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1])
{
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
return true;
#elif defined(__ANDROID__)
/* Android: dynamically check if getauxval is supported */
void* libc = NULL;
getauxval_function_t getauxval = NULL;
dlerror();
libc = dlopen("libc.so", RTLD_LAZY);
if (libc == NULL) {
cpuinfo_log_warning("failed to load libc.so: %s", dlerror());
goto cleanup;
}
getauxval = (getauxval_function_t) dlsym(libc, "getauxval");
if (getauxval == NULL) {
cpuinfo_log_info("failed to locate getauxval in libc.so: %s", dlerror());
goto cleanup;
}
*hwcap = getauxval(AT_HWCAP);
*hwcap2 = getauxval(AT_HWCAP2);
cleanup:
if (libc != NULL) {
dlclose(libc);
libc = NULL;
}
return getauxval != NULL;
#else
/* GNU/Linux: getauxval is always supported */
*hwcap = getauxval(AT_HWCAP);
*hwcap2 = getauxval(AT_HWCAP2);
return true;
#endif
}
#ifdef __ANDROID__
bool cpuinfo_arm_linux_hwcap_from_procfs(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1])
{
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
return true;
#else
uint32_t hwcaps[2] = { 0, 0 };
bool result = false;
int file = -1;
file = open("/proc/self/auxv", O_RDONLY);
if (file == -1) {
cpuinfo_log_warning("failed to open /proc/self/auxv: %s", strerror(errno));
goto cleanup;
}
ssize_t bytes_read;
do {
Elf32_auxv_t elf_auxv;
bytes_read = read(file, &elf_auxv, sizeof(Elf32_auxv_t));
if (bytes_read < 0) {
cpuinfo_log_warning("failed to read /proc/self/auxv: %s", strerror(errno));
goto cleanup;
} else if (bytes_read > 0) {
if (bytes_read == sizeof(elf_auxv)) {
switch (elf_auxv.a_type) {
case AT_HWCAP:
hwcaps[0] = (uint32_t) elf_auxv.a_un.a_val;
break;
case AT_HWCAP2:
hwcaps[1] = (uint32_t) elf_auxv.a_un.a_val;
break;
}
} else {
cpuinfo_log_warning(
"failed to read %zu bytes from /proc/self/auxv: %zu bytes available",
sizeof(elf_auxv), (size_t) bytes_read);
goto cleanup;
}
}
} while (bytes_read == sizeof(Elf32_auxv_t));
/* Success, commit results */
*hwcap = hwcaps[0];
*hwcap2 = hwcaps[1];
result = true;
cleanup:
if (file != -1) {
close(file);
file = -1;
}
return result;
#endif
}
#endif /* __ANDROID__ */
#elif CPUINFO_ARCH_ARM64
void cpuinfo_arm_linux_hwcap_from_getauxval(
uint32_t hwcap[restrict static 1],
uint32_t hwcap2[restrict static 1])
{
#if CPUINFO_MOCK
*hwcap = mock_hwcap;
*hwcap2 = mock_hwcap2;
#else
*hwcap = (uint32_t) getauxval(AT_HWCAP);
*hwcap2 = (uint32_t) getauxval(AT_HWCAP2);
return ;
#endif
}
#endif
|