xref: /aosp_15_r20/external/cpu_features/src/hwcaps.c (revision eca53ba6d2e951e174b64682eaf56a36b8204c89)
1*eca53ba6SRoland Levillain // Copyright 2017 Google LLC
2*eca53ba6SRoland Levillain //
3*eca53ba6SRoland Levillain // Licensed under the Apache License, Version 2.0 (the "License");
4*eca53ba6SRoland Levillain // you may not use this file except in compliance with the License.
5*eca53ba6SRoland Levillain // You may obtain a copy of the License at
6*eca53ba6SRoland Levillain //
7*eca53ba6SRoland Levillain //    http://www.apache.org/licenses/LICENSE-2.0
8*eca53ba6SRoland Levillain //
9*eca53ba6SRoland Levillain // Unless required by applicable law or agreed to in writing, software
10*eca53ba6SRoland Levillain // distributed under the License is distributed on an "AS IS" BASIS,
11*eca53ba6SRoland Levillain // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*eca53ba6SRoland Levillain // See the License for the specific language governing permissions and
13*eca53ba6SRoland Levillain // limitations under the License.
14*eca53ba6SRoland Levillain 
15*eca53ba6SRoland Levillain #include "internal/hwcaps.h"
16*eca53ba6SRoland Levillain 
17*eca53ba6SRoland Levillain #include <stdlib.h>
18*eca53ba6SRoland Levillain #include <string.h>
19*eca53ba6SRoland Levillain 
20*eca53ba6SRoland Levillain #include "cpu_features_macros.h"
21*eca53ba6SRoland Levillain #include "internal/filesystem.h"
22*eca53ba6SRoland Levillain #include "internal/string_view.h"
23*eca53ba6SRoland Levillain 
IsSet(const uint32_t mask,const uint32_t value)24*eca53ba6SRoland Levillain static bool IsSet(const uint32_t mask, const uint32_t value) {
25*eca53ba6SRoland Levillain   if (mask == 0) return false;
26*eca53ba6SRoland Levillain   return (value & mask) == mask;
27*eca53ba6SRoland Levillain }
28*eca53ba6SRoland Levillain 
CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,const HardwareCapabilities hwcaps)29*eca53ba6SRoland Levillain bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
30*eca53ba6SRoland Levillain                              const HardwareCapabilities hwcaps) {
31*eca53ba6SRoland Levillain   return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
32*eca53ba6SRoland Levillain          IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
33*eca53ba6SRoland Levillain }
34*eca53ba6SRoland Levillain 
35*eca53ba6SRoland Levillain #ifdef CPU_FEATURES_TEST
36*eca53ba6SRoland Levillain // In test mode, hwcaps_for_testing will define the following functions.
37*eca53ba6SRoland Levillain HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
38*eca53ba6SRoland Levillain const char* CpuFeatures_GetPlatformPointer(void);
39*eca53ba6SRoland Levillain const char* CpuFeatures_GetBasePlatformPointer(void);
40*eca53ba6SRoland Levillain #else
41*eca53ba6SRoland Levillain 
42*eca53ba6SRoland Levillain // Debug facilities
43*eca53ba6SRoland Levillain #if defined(NDEBUG)
44*eca53ba6SRoland Levillain #define D(...)
45*eca53ba6SRoland Levillain #else
46*eca53ba6SRoland Levillain #include <stdio.h>
47*eca53ba6SRoland Levillain #define D(...)           \
48*eca53ba6SRoland Levillain   do {                   \
49*eca53ba6SRoland Levillain     printf(__VA_ARGS__); \
50*eca53ba6SRoland Levillain     fflush(stdout);      \
51*eca53ba6SRoland Levillain   } while (0)
52*eca53ba6SRoland Levillain #endif
53*eca53ba6SRoland Levillain 
54*eca53ba6SRoland Levillain ////////////////////////////////////////////////////////////////////////////////
55*eca53ba6SRoland Levillain // Implementation of GetElfHwcapFromGetauxval
56*eca53ba6SRoland Levillain ////////////////////////////////////////////////////////////////////////////////
57*eca53ba6SRoland Levillain 
58*eca53ba6SRoland Levillain #define AT_HWCAP 16
59*eca53ba6SRoland Levillain #define AT_HWCAP2 26
60*eca53ba6SRoland Levillain #define AT_PLATFORM 15
61*eca53ba6SRoland Levillain #define AT_BASE_PLATFORM 24
62*eca53ba6SRoland Levillain 
63*eca53ba6SRoland Levillain #if defined(HAVE_STRONG_GETAUXVAL)
64*eca53ba6SRoland Levillain #include <sys/auxv.h>
GetElfHwcapFromGetauxval(uint32_t hwcap_type)65*eca53ba6SRoland Levillain static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
66*eca53ba6SRoland Levillain   return getauxval(hwcap_type);
67*eca53ba6SRoland Levillain }
68*eca53ba6SRoland Levillain #elif defined(HAVE_DLFCN_H)
69*eca53ba6SRoland Levillain // On Android we probe the system's C library for a 'getauxval' function and
70*eca53ba6SRoland Levillain // call it if it exits, or return 0 for failure. This function is available
71*eca53ba6SRoland Levillain // since API level 18.
72*eca53ba6SRoland Levillain //
73*eca53ba6SRoland Levillain // Note that getauxval() can't really be re-implemented here, because its
74*eca53ba6SRoland Levillain // implementation does not parse /proc/self/auxv. Instead it depends on values
75*eca53ba6SRoland Levillain // that are passed by the kernel at process-init time to the C runtime
76*eca53ba6SRoland Levillain // initialization layer.
77*eca53ba6SRoland Levillain 
78*eca53ba6SRoland Levillain #include <dlfcn.h>
79*eca53ba6SRoland Levillain 
80*eca53ba6SRoland Levillain typedef unsigned long getauxval_func_t(unsigned long);
81*eca53ba6SRoland Levillain 
GetElfHwcapFromGetauxval(uint32_t hwcap_type)82*eca53ba6SRoland Levillain static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
83*eca53ba6SRoland Levillain   uint32_t ret = 0;
84*eca53ba6SRoland Levillain   void *libc_handle = NULL;
85*eca53ba6SRoland Levillain   getauxval_func_t *func = NULL;
86*eca53ba6SRoland Levillain 
87*eca53ba6SRoland Levillain   dlerror();  // Cleaning error state before calling dlopen.
88*eca53ba6SRoland Levillain   libc_handle = dlopen("libc.so", RTLD_NOW);
89*eca53ba6SRoland Levillain   if (!libc_handle) {
90*eca53ba6SRoland Levillain     D("Could not dlopen() C library: %s\n", dlerror());
91*eca53ba6SRoland Levillain     return 0;
92*eca53ba6SRoland Levillain   }
93*eca53ba6SRoland Levillain   func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
94*eca53ba6SRoland Levillain   if (!func) {
95*eca53ba6SRoland Levillain     D("Could not find getauxval() in C library\n");
96*eca53ba6SRoland Levillain   } else {
97*eca53ba6SRoland Levillain     // Note: getauxval() returns 0 on failure. Doesn't touch errno.
98*eca53ba6SRoland Levillain     ret = (uint32_t)(*func)(hwcap_type);
99*eca53ba6SRoland Levillain   }
100*eca53ba6SRoland Levillain   dlclose(libc_handle);
101*eca53ba6SRoland Levillain   return ret;
102*eca53ba6SRoland Levillain }
103*eca53ba6SRoland Levillain #else
104*eca53ba6SRoland Levillain #error "This platform does not provide hardware capabilities."
105*eca53ba6SRoland Levillain #endif
106*eca53ba6SRoland Levillain 
107*eca53ba6SRoland Levillain // Implementation of GetHardwareCapabilities for OS that provide
108*eca53ba6SRoland Levillain // GetElfHwcapFromGetauxval().
109*eca53ba6SRoland Levillain 
110*eca53ba6SRoland Levillain // Fallback when getauxval is not available, retrieves hwcaps from
111*eca53ba6SRoland Levillain // "/proc/self/auxv".
GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type)112*eca53ba6SRoland Levillain static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
113*eca53ba6SRoland Levillain   struct {
114*eca53ba6SRoland Levillain     uint32_t tag;
115*eca53ba6SRoland Levillain     uint32_t value;
116*eca53ba6SRoland Levillain   } entry;
117*eca53ba6SRoland Levillain   uint32_t result = 0;
118*eca53ba6SRoland Levillain   const char filepath[] = "/proc/self/auxv";
119*eca53ba6SRoland Levillain   const int fd = CpuFeatures_OpenFile(filepath);
120*eca53ba6SRoland Levillain   if (fd < 0) {
121*eca53ba6SRoland Levillain     D("Could not open %s\n", filepath);
122*eca53ba6SRoland Levillain     return 0;
123*eca53ba6SRoland Levillain   }
124*eca53ba6SRoland Levillain   for (;;) {
125*eca53ba6SRoland Levillain     const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
126*eca53ba6SRoland Levillain     if (ret < 0) {
127*eca53ba6SRoland Levillain       D("Error while reading %s\n", filepath);
128*eca53ba6SRoland Levillain       break;
129*eca53ba6SRoland Levillain     }
130*eca53ba6SRoland Levillain     // Detect end of list.
131*eca53ba6SRoland Levillain     if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
132*eca53ba6SRoland Levillain       break;
133*eca53ba6SRoland Levillain     }
134*eca53ba6SRoland Levillain     if (entry.tag == hwcap_type) {
135*eca53ba6SRoland Levillain       result = entry.value;
136*eca53ba6SRoland Levillain       break;
137*eca53ba6SRoland Levillain     }
138*eca53ba6SRoland Levillain   }
139*eca53ba6SRoland Levillain   CpuFeatures_CloseFile(fd);
140*eca53ba6SRoland Levillain   return result;
141*eca53ba6SRoland Levillain }
142*eca53ba6SRoland Levillain 
143*eca53ba6SRoland Levillain // Retrieves hardware capabilities by first trying to call getauxval, if not
144*eca53ba6SRoland Levillain // available falls back to reading "/proc/self/auxv".
GetHardwareCapabilitiesFor(uint32_t type)145*eca53ba6SRoland Levillain static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
146*eca53ba6SRoland Levillain   unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
147*eca53ba6SRoland Levillain   if (!hwcaps) {
148*eca53ba6SRoland Levillain     D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
149*eca53ba6SRoland Levillain     hwcaps = GetElfHwcapFromProcSelfAuxv(type);
150*eca53ba6SRoland Levillain   }
151*eca53ba6SRoland Levillain   return hwcaps;
152*eca53ba6SRoland Levillain }
153*eca53ba6SRoland Levillain 
CpuFeatures_GetHardwareCapabilities(void)154*eca53ba6SRoland Levillain HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
155*eca53ba6SRoland Levillain   HardwareCapabilities capabilities;
156*eca53ba6SRoland Levillain   capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
157*eca53ba6SRoland Levillain   capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
158*eca53ba6SRoland Levillain   return capabilities;
159*eca53ba6SRoland Levillain }
160*eca53ba6SRoland Levillain 
CpuFeatures_GetPlatformPointer(void)161*eca53ba6SRoland Levillain const char *CpuFeatures_GetPlatformPointer(void) {
162*eca53ba6SRoland Levillain   return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
163*eca53ba6SRoland Levillain }
164*eca53ba6SRoland Levillain 
CpuFeatures_GetBasePlatformPointer(void)165*eca53ba6SRoland Levillain const char *CpuFeatures_GetBasePlatformPointer(void) {
166*eca53ba6SRoland Levillain   return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
167*eca53ba6SRoland Levillain }
168*eca53ba6SRoland Levillain 
169*eca53ba6SRoland Levillain #endif  // CPU_FEATURES_TEST
170