blob: 815e5c185c7d07268e1377d38983ac8d3cfa0db6 [file] [log] [blame]
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001// Copyright 2017 Google Inc.
2//
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
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
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.
14
Rashmica Guptac45e32f2018-05-02 14:30:25 +100015#include <stdlib.h>
16#include <string.h>
17
Guillaume Chatelet439d3712018-02-01 10:03:09 +010018#include "cpu_features_macros.h"
19#include "internal/filesystem.h"
Rashmica Guptac45e32f2018-05-02 14:30:25 +100020#include "internal/hwcaps.h"
21#include "internal/string_view.h"
Guillaume Chatelet439d3712018-02-01 10:03:09 +010022
23#if defined(NDEBUG)
24#define D(...)
25#else
26#include <stdio.h>
27#define D(...) \
28 do { \
29 printf(__VA_ARGS__); \
30 fflush(stdout); \
31 } while (0)
32#endif
33
Guillaume Chatelet439d3712018-02-01 10:03:09 +010034////////////////////////////////////////////////////////////////////////////////
35// Implementation of GetElfHwcapFromGetauxval
36////////////////////////////////////////////////////////////////////////////////
37
Guillaume Chatelete8e56102019-01-15 10:52:56 +010038#if defined(CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL)
39// Implementation will be provided by test/hwcaps_for_testing.cc.
Guillaume Chatelet122b0672019-01-15 15:18:08 +010040#elif defined(HAVE_STRONG_GETAUXVAL)
41#include <sys/auxv.h>
42static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
43 return getauxval(hwcap_type);
44}
45#elif defined(HAVE_DLFCN_H)
Guillaume Chatelet439d3712018-02-01 10:03:09 +010046// On Android we probe the system's C library for a 'getauxval' function and
47// call it if it exits, or return 0 for failure. This function is available
48// since API level 20.
49//
50// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
51// case where some NDK developers use headers for a platform that is newer than
52// the one really targetted by their application. This is typically done to use
53// newer native APIs only when running on more recent Android versions, and
54// requires careful symbol management.
55//
56// Note that getauxval() can't really be re-implemented here, because its
57// implementation does not parse /proc/self/auxv. Instead it depends on values
58// that are passed by the kernel at process-init time to the C runtime
59// initialization layer.
Guillaume Chatelete8e56102019-01-15 10:52:56 +010060
Guillaume Chatelet439d3712018-02-01 10:03:09 +010061#include <dlfcn.h>
62#define AT_HWCAP 16
63#define AT_HWCAP2 26
Rashmica Guptac45e32f2018-05-02 14:30:25 +100064#define AT_PLATFORM 15
65#define AT_BASE_PLATFORM 24
66
Guillaume Chatelet439d3712018-02-01 10:03:09 +010067typedef unsigned long getauxval_func_t(unsigned long);
68
69static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
70 uint32_t ret = 0;
71 void* libc_handle = NULL;
72 getauxval_func_t* func = NULL;
73
74 dlerror(); // Cleaning error state before calling dlopen.
75 libc_handle = dlopen("libc.so", RTLD_NOW);
76 if (!libc_handle) {
77 D("Could not dlopen() C library: %s\n", dlerror());
78 return 0;
79 }
80 func = (getauxval_func_t*)dlsym(libc_handle, "getauxval");
81 if (!func) {
82 D("Could not find getauxval() in C library\n");
83 } else {
84 // Note: getauxval() returns 0 on failure. Doesn't touch errno.
85 ret = (uint32_t)(*func)(hwcap_type);
86 }
87 dlclose(libc_handle);
88 return ret;
89}
Guillaume Chatelete8e56102019-01-15 10:52:56 +010090#else
91#error "This platform does not provide hardware capabilities."
92#endif
Guillaume Chatelet439d3712018-02-01 10:03:09 +010093
Guillaume Chatelete8e56102019-01-15 10:52:56 +010094// Implementation of GetHardwareCapabilities for OS that provide
95// GetElfHwcapFromGetauxval().
Guillaume Chatelet439d3712018-02-01 10:03:09 +010096
97// Fallback when getauxval is not available, retrieves hwcaps from
98// "/proc/self/auxv".
99static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
100 struct {
101 uint32_t tag;
102 uint32_t value;
103 } entry;
104 uint32_t result = 0;
105 const char filepath[] = "/proc/self/auxv";
Arvid Gerstmann235d57c2018-05-04 09:30:32 +0200106 const int fd = CpuFeatures_OpenFile(filepath);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100107 if (fd < 0) {
108 D("Could not open %s\n", filepath);
109 return 0;
110 }
111 for (;;) {
Arvid Gerstmann235d57c2018-05-04 09:30:32 +0200112 const int ret = CpuFeatures_ReadFile(fd, (char*)&entry, sizeof entry);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100113 if (ret < 0) {
114 D("Error while reading %s\n", filepath);
115 break;
116 }
117 // Detect end of list.
118 if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
119 break;
120 }
121 if (entry.tag == hwcap_type) {
122 result = entry.value;
123 break;
124 }
125 }
Arvid Gerstmann235d57c2018-05-04 09:30:32 +0200126 CpuFeatures_CloseFile(fd);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100127 return result;
128}
129
130// Retrieves hardware capabilities by first trying to call getauxval, if not
131// available falls back to reading "/proc/self/auxv".
Rashmica Gupta1c8bf0e2018-04-27 11:53:51 +1000132static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
133 unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100134 if (!hwcaps) {
135 D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
136 hwcaps = GetElfHwcapFromProcSelfAuxv(type);
137 }
138 return hwcaps;
139}
140
Arvid Gerstmannfd483902018-05-03 17:07:07 +0200141HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100142 HardwareCapabilities capabilities;
143 capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
144 capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
145 return capabilities;
146}
147
Rashmica Guptac45e32f2018-05-02 14:30:25 +1000148PlatformType kEmptyPlatformType;
149
150PlatformType CpuFeatures_GetPlatformType(void) {
151 PlatformType type = kEmptyPlatformType;
152 char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
153 char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
154
155 if (platform != NULL)
156 CpuFeatures_StringView_CopyString(str(platform), type.platform,
157 sizeof(type.platform));
158 if (base_platform != NULL)
159 CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
160 sizeof(type.base_platform));
161 return type;
162}