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