1 // Copyright 2017 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
18 #include "cpu_features_macros.h"
19 #include "internal/filesystem.h"
20 #include "internal/hwcaps.h"
21 #include "internal/string_view.h"
29 printf(__VA_ARGS__); \
34 #if defined(CPU_FEATURES_ARCH_MIPS) || defined(CPU_FEATURES_ARCH_ANY_ARM)
35 #define HWCAPS_ANDROID_MIPS_OR_ARM
38 #if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID) && \
39 !defined(HWCAPS_ANDROID_MIPS_OR_ARM)
40 #define HWCAPS_REGULAR_LINUX
43 #if defined(HWCAPS_ANDROID_MIPS_OR_ARM) || defined(HWCAPS_REGULAR_LINUX)
44 #define HWCAPS_SUPPORTED
47 ////////////////////////////////////////////////////////////////////////////////
48 // Implementation of GetElfHwcapFromGetauxval
49 ////////////////////////////////////////////////////////////////////////////////
51 // On Linux we simply use getauxval.
52 #if defined(HWCAPS_REGULAR_LINUX)
55 static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
56 return getauxval(hwcap_type);
58 #endif // defined(HWCAPS_REGULAR_LINUX)
60 // On Android we probe the system's C library for a 'getauxval' function and
61 // call it if it exits, or return 0 for failure. This function is available
62 // since API level 20.
64 // This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
65 // case where some NDK developers use headers for a platform that is newer than
66 // the one really targetted by their application. This is typically done to use
67 // newer native APIs only when running on more recent Android versions, and
68 // requires careful symbol management.
70 // Note that getauxval() can't really be re-implemented here, because its
71 // implementation does not parse /proc/self/auxv. Instead it depends on values
72 // that are passed by the kernel at process-init time to the C runtime
73 // initialization layer.
74 #if defined(HWCAPS_ANDROID_MIPS_OR_ARM)
78 #define AT_PLATFORM 15
79 #define AT_BASE_PLATFORM 24
81 typedef unsigned long getauxval_func_t(unsigned long);
83 static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
85 void* libc_handle = NULL;
86 getauxval_func_t* func = NULL;
88 dlerror(); // Cleaning error state before calling dlopen.
89 libc_handle = dlopen("libc.so", RTLD_NOW);
91 D("Could not dlopen() C library: %s\n", dlerror());
94 func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
96 D("Could not find getauxval() in C library\n");
98 // Note: getauxval() returns 0 on failure. Doesn't touch errno.
99 ret = (uint32_t)(*func)(hwcap_type);
101 dlclose(libc_handle);
104 #endif // defined(HWCAPS_ANDROID_MIPS_OR_ARM)
106 #if defined(HWCAPS_SUPPORTED)
107 ////////////////////////////////////////////////////////////////////////////////
108 // Implementation of GetHardwareCapabilities for Android and Linux
109 ////////////////////////////////////////////////////////////////////////////////
111 // Fallback when getauxval is not available, retrieves hwcaps from
112 // "/proc/self/auxv".
113 static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
119 const char filepath[] = "/proc/self/auxv";
120 const int fd = CpuFeatures_OpenFile(filepath);
122 D("Could not open %s\n", filepath);
126 const int ret = CpuFeatures_ReadFile(fd, (char*)&entry, sizeof entry);
128 D("Error while reading %s\n", filepath);
131 // Detect end of list.
132 if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
135 if (entry.tag == hwcap_type) {
136 result = entry.value;
140 CpuFeatures_CloseFile(fd);
144 // Retrieves hardware capabilities by first trying to call getauxval, if not
145 // available falls back to reading "/proc/self/auxv".
146 static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
147 unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
149 D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
150 hwcaps = GetElfHwcapFromProcSelfAuxv(type);
155 HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
156 HardwareCapabilities capabilities;
157 capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
158 capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
162 PlatformType kEmptyPlatformType;
164 PlatformType CpuFeatures_GetPlatformType(void) {
165 PlatformType type = kEmptyPlatformType;
166 char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
167 char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
169 if (platform != NULL)
170 CpuFeatures_StringView_CopyString(str(platform), type.platform,
171 sizeof(type.platform));
172 if (base_platform != NULL)
173 CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
174 sizeof(type.base_platform));
177 #else // (defined(HWCAPS_SUPPORTED)
179 ////////////////////////////////////////////////////////////////////////////////
180 // Implementation of GetHardwareCapabilities for unsupported platforms.
181 ////////////////////////////////////////////////////////////////////////////////
183 const HardwareCapabilities kEmptyHardwareCapabilities;
184 HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
185 return kEmptyHardwareCapabilities;