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