xref: /aosp_15_r20/external/cpuinfo/src/arm/linux/hwcap.c (revision 2b54f0db79fd8303838913b20ff3780cddaa909f)
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