blob: 822581cabfcf3475fead82858fe336ae4e345f9b [file] [log] [blame]
Haibo Huangea9957a2018-11-19 11:00:32 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <fcntl.h>
30#include <sys/syscall.h>
31
32extern "C" {
33
34enum CpuVariant {
35 kUnknown = 0,
36 kGeneric,
37 kCortexA7,
38 kCortexA9,
39 kCortexA53,
40 kCortexA55,
41 kDenver,
42 kKrait,
43 kKryo,
44};
45
46static constexpr int MAX_CPU_NAME_LEN = 12;
47struct CpuVariantNames {
Haibo Huang73ad7902018-11-28 22:56:58 -080048 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
Haibo Huangea9957a2018-11-19 11:00:32 -080049 CpuVariant variant;
50};
51
52static constexpr CpuVariantNames cpu_variant_names[] = {
53 {"cortex-a76", kCortexA55},
54 {"cortex-a75", kCortexA55},
55 {"kryo", kKryo},
56 {"cortex-a73", kCortexA55},
57 {"cortex-a55", kCortexA55},
58 {"cortex-a53", kCortexA53},
59 {"krait", kKrait},
60 {"cortex-a9", kCortexA9},
61 {"cortex-a7", kCortexA7},
62 {"denver", kDenver},
63 // kUnknown indicates the end of this array.
64 {"", kUnknown},
65};
66
67static long ifunc_open(const char* pathname) {
68 register long r0 __asm__("r0") = AT_FDCWD;
69 register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
70 register long r2 __asm__("r2") = O_RDONLY;
71 register long r3 __asm__("r3") = 0;
72 register long r7 __asm__("r7") = __NR_openat;
73 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
74 return r0;
75}
76
77static ssize_t ifunc_read(int fd, void* buf, size_t count) {
78 register long r0 __asm__("r0") = fd;
79 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
80 register long r2 __asm__("r2") = count;
81 register long r7 __asm__("r7") = __NR_read;
82 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
83 return r0;
84}
85
86static int ifunc_close(int fd) {
87 register long r0 __asm__("r0") = fd;
88 register long r7 __asm__("r7") = __NR_close;
89 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
90 return r0;
91}
92
93#define DEFINE_IFUNC(name) \
94 name##_func name __attribute__((ifunc(#name "_resolver"))); \
95 __attribute__((visibility("hidden"))) \
96 name##_func* name##_resolver()
97
98#define DECLARE_FUNC(type, name) \
99 __attribute__((visibility("hidden"))) \
100 type name
101
102#define RETURN_FUNC(type, name) { \
103 DECLARE_FUNC(type, name); \
104 return name; \
105 }
106
Haibo Huang73ad7902018-11-28 22:56:58 -0800107static bool is_same_name(const char* a, const char* b) {
108 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
109 const int* ia = reinterpret_cast<const int*>(a);
110 const int* ib = reinterpret_cast<const int*>(b);
111 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
112 if (ia[i] != ib[i]) {
113 return false;
114 }
115 }
116 return true;
117}
118
Haibo Huangea9957a2018-11-19 11:00:32 -0800119static CpuVariant init_cpu_variant() {
120 int fd = ifunc_open("/dev/cpu_variant:arm");
121 if (fd < 0) return kGeneric;
122
Haibo Huang73ad7902018-11-28 22:56:58 -0800123 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800124
125 int bytes_read, total_read = 0;
126 while (total_read < MAX_CPU_NAME_LEN - 1 &&
127 (bytes_read = ifunc_read(fd, name + total_read,
128 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
129 total_read += bytes_read;
130 }
131 ifunc_close(fd);
132
133 if (bytes_read != 0) {
134 // The file is too big. We haven't reach the end. Or maybe there is an
135 // error when reading.
136 return kGeneric;
137 }
138 name[total_read] = 0;
139
Haibo Huangea9957a2018-11-19 11:00:32 -0800140 const CpuVariantNames* cpu_variant = cpu_variant_names;
141 while (cpu_variant->variant != kUnknown) {
Haibo Huang73ad7902018-11-28 22:56:58 -0800142 if (is_same_name(cpu_variant->name, name)) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800143 return cpu_variant->variant;
144 }
145 cpu_variant++;
146 }
147 return kGeneric;
148}
149
150static CpuVariant get_cpu_variant() {
151 static CpuVariant cpu_variant = kUnknown;
152 if (cpu_variant == kUnknown) {
153 cpu_variant = init_cpu_variant();
154 }
155 return cpu_variant;
156}
157
158typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
159DEFINE_IFUNC(memmove) {
160 switch(get_cpu_variant()) {
161 case kCortexA7:
162 RETURN_FUNC(memmove_func, memmove_a7);
163 case kCortexA9:
164 RETURN_FUNC(memmove_func, memmove_a9);
165 case kKrait:
166 RETURN_FUNC(memmove_func, memmove_krait);
167 case kCortexA53:
168 RETURN_FUNC(memmove_func, memmove_a53);
169 case kCortexA55:
170 case kDenver:
171 RETURN_FUNC(memmove_func, memmove_denver);
172 case kKryo:
173 RETURN_FUNC(memmove_func, memmove_kryo);
174 default:
175 RETURN_FUNC(memmove_func, memmove_a15);
176 }
177}
178
179typedef void* memcpy_func(void*, const void*, size_t);
180DEFINE_IFUNC(memcpy) {
181 return memmove_resolver();
182}
183
184typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
185DEFINE_IFUNC(__memset_chk) {
186 switch(get_cpu_variant()) {
187 case kCortexA7:
188 case kCortexA53:
189 case kCortexA55:
190 case kKryo:
191 RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
192 case kCortexA9:
193 RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
194 case kKrait:
195 RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
196 case kDenver:
197 RETURN_FUNC(__memset_chk_func, __memset_chk_denver);
198 default:
199 RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
200 }
201}
202
203typedef void* memset_func(void* __dst, int __ch, size_t __n);
204DEFINE_IFUNC(memset) {
205 switch(get_cpu_variant()) {
206 case kCortexA7:
207 case kCortexA53:
208 case kCortexA55:
209 case kKryo:
210 RETURN_FUNC(memset_func, memset_a7);
211 case kCortexA9:
212 RETURN_FUNC(memset_func, memset_a9);
213 case kKrait:
214 RETURN_FUNC(memset_func, memset_krait);
215 case kDenver:
216 RETURN_FUNC(memset_func, memset_denver);
217 default:
218 RETURN_FUNC(memset_func, memset_a15);
219 }
220}
221
222typedef char* strcpy_func(char* __dst, const char* __src);
223DEFINE_IFUNC(strcpy) {
224 switch(get_cpu_variant()) {
225 case kCortexA9:
226 RETURN_FUNC(strcpy_func, strcpy_a9);
227 default:
228 RETURN_FUNC(strcpy_func, strcpy_a15);
229 }
230}
231
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800232typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
233DEFINE_IFUNC(__strcpy_chk) {
234 switch(get_cpu_variant()) {
235 case kCortexA7:
236 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
237 case kCortexA9:
238 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
239 case kKrait:
240 case kKryo:
241 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
242 case kCortexA53:
243 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
244 case kCortexA55:
245 case kDenver:
246 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_denver);
247 default:
248 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
249 }
250}
251
Haibo Huangea9957a2018-11-19 11:00:32 -0800252typedef char* stpcpy_func(char* __dst, const char* __src);
253DEFINE_IFUNC(stpcpy) {
254 switch(get_cpu_variant()) {
255 case kCortexA9:
256 RETURN_FUNC(stpcpy_func, stpcpy_a9);
257 default:
258 RETURN_FUNC(stpcpy_func, stpcpy_a15);
259 }
260}
261
262typedef char* strcat_func(char* __dst, const char* __src);
263DEFINE_IFUNC(strcat) {
264 switch(get_cpu_variant()) {
265 case kCortexA9:
266 RETURN_FUNC(strcat_func, strcat_a9);
267 default:
268 RETURN_FUNC(strcat_func, strcat_a15);
269 }
270}
271
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800272typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
273DEFINE_IFUNC(__strcat_chk) {
274 switch(get_cpu_variant()) {
275 case kCortexA7:
276 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
277 case kCortexA9:
278 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
279 case kKrait:
280 case kKryo:
281 RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
282 case kCortexA53:
283 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
284 case kCortexA55:
285 case kDenver:
286 RETURN_FUNC(__strcat_chk_func, __strcat_chk_denver);
287 default:
288 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
289 }
290}
291
Haibo Huangea9957a2018-11-19 11:00:32 -0800292typedef int strcmp_func(const char* __lhs, const char* __rhs);
293DEFINE_IFUNC(strcmp) {
294 switch(get_cpu_variant()) {
295 case kCortexA9:
296 RETURN_FUNC(strcmp_func, strcmp_a9);
297 case kCortexA55:
298 case kKrait:
299 case kKryo:
300 RETURN_FUNC(strcmp_func, strcmp_krait);
301 default:
302 RETURN_FUNC(strcmp_func, strcmp_a15);
303 }
304}
305
306typedef size_t strlen_func(const char* __s);
307DEFINE_IFUNC(strlen) {
308 switch(get_cpu_variant()) {
309 case kCortexA9:
310 RETURN_FUNC(strlen_func, strlen_a9);
311 default:
312 RETURN_FUNC(strlen_func, strlen_a15);
313 }
314}
315
316} // extern "C"