blob: 72fb41c2b283cf90444c9b96b8acbfea21daa2ea [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,
Haibo Huangea9957a2018-11-19 11:00:32 -080041 kKrait,
42 kKryo,
43};
44
45static constexpr int MAX_CPU_NAME_LEN = 12;
46struct CpuVariantNames {
Haibo Huang73ad7902018-11-28 22:56:58 -080047 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
Haibo Huangea9957a2018-11-19 11:00:32 -080048 CpuVariant variant;
49};
50
51static constexpr CpuVariantNames cpu_variant_names[] = {
52 {"cortex-a76", kCortexA55},
53 {"cortex-a75", kCortexA55},
54 {"kryo", kKryo},
55 {"cortex-a73", kCortexA55},
56 {"cortex-a55", kCortexA55},
57 {"cortex-a53", kCortexA53},
58 {"krait", kKrait},
59 {"cortex-a9", kCortexA9},
60 {"cortex-a7", kCortexA7},
Haibo Huangea9957a2018-11-19 11:00:32 -080061 // kUnknown indicates the end of this array.
62 {"", kUnknown},
63};
64
65static long ifunc_open(const char* pathname) {
66 register long r0 __asm__("r0") = AT_FDCWD;
67 register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
68 register long r2 __asm__("r2") = O_RDONLY;
69 register long r3 __asm__("r3") = 0;
70 register long r7 __asm__("r7") = __NR_openat;
71 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
72 return r0;
73}
74
75static ssize_t ifunc_read(int fd, void* buf, size_t count) {
76 register long r0 __asm__("r0") = fd;
77 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
78 register long r2 __asm__("r2") = count;
79 register long r7 __asm__("r7") = __NR_read;
80 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
81 return r0;
82}
83
84static int ifunc_close(int fd) {
85 register long r0 __asm__("r0") = fd;
86 register long r7 __asm__("r7") = __NR_close;
87 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
88 return r0;
89}
90
91#define DEFINE_IFUNC(name) \
92 name##_func name __attribute__((ifunc(#name "_resolver"))); \
93 __attribute__((visibility("hidden"))) \
94 name##_func* name##_resolver()
95
96#define DECLARE_FUNC(type, name) \
97 __attribute__((visibility("hidden"))) \
98 type name
99
100#define RETURN_FUNC(type, name) { \
101 DECLARE_FUNC(type, name); \
102 return name; \
103 }
104
Haibo Huang73ad7902018-11-28 22:56:58 -0800105static bool is_same_name(const char* a, const char* b) {
106 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
107 const int* ia = reinterpret_cast<const int*>(a);
108 const int* ib = reinterpret_cast<const int*>(b);
109 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
110 if (ia[i] != ib[i]) {
111 return false;
112 }
113 }
114 return true;
115}
116
Haibo Huangea9957a2018-11-19 11:00:32 -0800117static CpuVariant init_cpu_variant() {
118 int fd = ifunc_open("/dev/cpu_variant:arm");
119 if (fd < 0) return kGeneric;
120
Haibo Huang73ad7902018-11-28 22:56:58 -0800121 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800122
123 int bytes_read, total_read = 0;
124 while (total_read < MAX_CPU_NAME_LEN - 1 &&
125 (bytes_read = ifunc_read(fd, name + total_read,
126 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
127 total_read += bytes_read;
128 }
129 ifunc_close(fd);
130
131 if (bytes_read != 0) {
132 // The file is too big. We haven't reach the end. Or maybe there is an
133 // error when reading.
134 return kGeneric;
135 }
136 name[total_read] = 0;
137
Haibo Huangea9957a2018-11-19 11:00:32 -0800138 const CpuVariantNames* cpu_variant = cpu_variant_names;
139 while (cpu_variant->variant != kUnknown) {
Haibo Huang73ad7902018-11-28 22:56:58 -0800140 if (is_same_name(cpu_variant->name, name)) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800141 return cpu_variant->variant;
142 }
143 cpu_variant++;
144 }
145 return kGeneric;
146}
147
148static CpuVariant get_cpu_variant() {
149 static CpuVariant cpu_variant = kUnknown;
150 if (cpu_variant == kUnknown) {
151 cpu_variant = init_cpu_variant();
152 }
153 return cpu_variant;
154}
155
156typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
157DEFINE_IFUNC(memmove) {
Haibo Huang01bfd892018-12-03 15:05:16 -0800158 RETURN_FUNC(memmove_func, memmove_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800159}
160
161typedef void* memcpy_func(void*, const void*, size_t);
162DEFINE_IFUNC(memcpy) {
163 return memmove_resolver();
164}
165
Haibo Huang01bfd892018-12-03 15:05:16 -0800166typedef void* __memcpy_func(void*, const void*, size_t);
167DEFINE_IFUNC(__memcpy) {
168 switch(get_cpu_variant()) {
169 case kCortexA7:
170 RETURN_FUNC(__memcpy_func, __memcpy_a7);
171 case kCortexA9:
172 RETURN_FUNC(__memcpy_func, __memcpy_a9);
173 case kKrait:
174 RETURN_FUNC(__memcpy_func, __memcpy_krait);
175 case kCortexA53:
176 RETURN_FUNC(__memcpy_func, __memcpy_a53);
177 case kCortexA55:
178 RETURN_FUNC(__memcpy_func, __memcpy_a55);
179 case kKryo:
180 RETURN_FUNC(__memcpy_func, __memcpy_kryo);
181 default:
182 RETURN_FUNC(__memcpy_func, __memcpy_a15);
183 }
184}
185
Haibo Huangea9957a2018-11-19 11:00:32 -0800186typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
187DEFINE_IFUNC(__memset_chk) {
188 switch(get_cpu_variant()) {
189 case kCortexA7:
190 case kCortexA53:
191 case kCortexA55:
192 case kKryo:
193 RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
194 case kCortexA9:
195 RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
196 case kKrait:
197 RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800198 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);
Haibo Huangea9957a2018-11-19 11:00:32 -0800215 default:
216 RETURN_FUNC(memset_func, memset_a15);
217 }
218}
219
220typedef char* strcpy_func(char* __dst, const char* __src);
221DEFINE_IFUNC(strcpy) {
222 switch(get_cpu_variant()) {
223 case kCortexA9:
224 RETURN_FUNC(strcpy_func, strcpy_a9);
225 default:
226 RETURN_FUNC(strcpy_func, strcpy_a15);
227 }
228}
229
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800230typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
231DEFINE_IFUNC(__strcpy_chk) {
232 switch(get_cpu_variant()) {
233 case kCortexA7:
234 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
235 case kCortexA9:
236 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
237 case kKrait:
238 case kKryo:
239 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
240 case kCortexA53:
241 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
242 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800243 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800244 default:
245 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
246 }
247}
248
Haibo Huangea9957a2018-11-19 11:00:32 -0800249typedef char* stpcpy_func(char* __dst, const char* __src);
250DEFINE_IFUNC(stpcpy) {
251 switch(get_cpu_variant()) {
252 case kCortexA9:
253 RETURN_FUNC(stpcpy_func, stpcpy_a9);
254 default:
255 RETURN_FUNC(stpcpy_func, stpcpy_a15);
256 }
257}
258
259typedef char* strcat_func(char* __dst, const char* __src);
260DEFINE_IFUNC(strcat) {
261 switch(get_cpu_variant()) {
262 case kCortexA9:
263 RETURN_FUNC(strcat_func, strcat_a9);
264 default:
265 RETURN_FUNC(strcat_func, strcat_a15);
266 }
267}
268
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800269typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
270DEFINE_IFUNC(__strcat_chk) {
271 switch(get_cpu_variant()) {
272 case kCortexA7:
273 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
274 case kCortexA9:
275 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
276 case kKrait:
277 case kKryo:
278 RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
279 case kCortexA53:
280 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
281 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800282 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800283 default:
284 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
285 }
286}
287
Haibo Huangea9957a2018-11-19 11:00:32 -0800288typedef int strcmp_func(const char* __lhs, const char* __rhs);
289DEFINE_IFUNC(strcmp) {
290 switch(get_cpu_variant()) {
291 case kCortexA9:
292 RETURN_FUNC(strcmp_func, strcmp_a9);
293 case kCortexA55:
294 case kKrait:
295 case kKryo:
296 RETURN_FUNC(strcmp_func, strcmp_krait);
297 default:
298 RETURN_FUNC(strcmp_func, strcmp_a15);
299 }
300}
301
302typedef size_t strlen_func(const char* __s);
303DEFINE_IFUNC(strlen) {
304 switch(get_cpu_variant()) {
305 case kCortexA9:
306 RETURN_FUNC(strlen_func, strlen_a9);
307 default:
308 RETURN_FUNC(strlen_func, strlen_a15);
309 }
310}
311
312} // extern "C"