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