blob: 09fd8f30e2fc8b3097b56bc0273b5d041399affb [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},
Haibo Huang4af19612018-12-04 12:54:43 -080053 {"kryo385", kCortexA55},
Haibo Huangea9957a2018-11-19 11:00:32 -080054 {"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},
Haibo Huangea9957a2018-11-19 11:00:32 -080062 // kUnknown indicates the end of this array.
63 {"", kUnknown},
64};
65
66static long ifunc_open(const char* pathname) {
67 register long r0 __asm__("r0") = AT_FDCWD;
68 register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
69 register long r2 __asm__("r2") = O_RDONLY;
70 register long r3 __asm__("r3") = 0;
71 register long r7 __asm__("r7") = __NR_openat;
72 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
73 return r0;
74}
75
76static ssize_t ifunc_read(int fd, void* buf, size_t count) {
77 register long r0 __asm__("r0") = fd;
78 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
79 register long r2 __asm__("r2") = count;
80 register long r7 __asm__("r7") = __NR_read;
81 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
82 return r0;
83}
84
85static int ifunc_close(int fd) {
86 register long r0 __asm__("r0") = fd;
87 register long r7 __asm__("r7") = __NR_close;
88 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
89 return r0;
90}
91
Haibo Huange4788d42018-12-11 20:28:02 -080092#define DEFINE_IFUNC_WITH_SUFFIX(name, suffix) \
93 name##_func name##suffix __attribute__((ifunc(#name "_resolver"))); \
Haibo Huangea9957a2018-11-19 11:00:32 -080094 __attribute__((visibility("hidden"))) \
95 name##_func* name##_resolver()
96
Haibo Huange4788d42018-12-11 20:28:02 -080097#define DEFINE_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, )
98
99#define DEFINE_INTERNAL_IFUNC(name) DEFINE_IFUNC_WITH_SUFFIX(name, _internal)
100
Haibo Huangea9957a2018-11-19 11:00:32 -0800101#define DECLARE_FUNC(type, name) \
102 __attribute__((visibility("hidden"))) \
103 type name
104
105#define RETURN_FUNC(type, name) { \
106 DECLARE_FUNC(type, name); \
107 return name; \
108 }
109
Haibo Huang73ad7902018-11-28 22:56:58 -0800110static bool is_same_name(const char* a, const char* b) {
111 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
112 const int* ia = reinterpret_cast<const int*>(a);
113 const int* ib = reinterpret_cast<const int*>(b);
114 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
115 if (ia[i] != ib[i]) {
116 return false;
117 }
118 }
119 return true;
120}
121
Haibo Huangea9957a2018-11-19 11:00:32 -0800122static CpuVariant init_cpu_variant() {
123 int fd = ifunc_open("/dev/cpu_variant:arm");
124 if (fd < 0) return kGeneric;
125
Haibo Huang73ad7902018-11-28 22:56:58 -0800126 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800127
128 int bytes_read, total_read = 0;
129 while (total_read < MAX_CPU_NAME_LEN - 1 &&
130 (bytes_read = ifunc_read(fd, name + total_read,
131 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
132 total_read += bytes_read;
133 }
134 ifunc_close(fd);
135
136 if (bytes_read != 0) {
137 // The file is too big. We haven't reach the end. Or maybe there is an
138 // error when reading.
139 return kGeneric;
140 }
141 name[total_read] = 0;
142
Haibo Huangea9957a2018-11-19 11:00:32 -0800143 const CpuVariantNames* cpu_variant = cpu_variant_names;
144 while (cpu_variant->variant != kUnknown) {
Haibo Huang73ad7902018-11-28 22:56:58 -0800145 if (is_same_name(cpu_variant->name, name)) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800146 return cpu_variant->variant;
147 }
148 cpu_variant++;
149 }
150 return kGeneric;
151}
152
153static CpuVariant get_cpu_variant() {
154 static CpuVariant cpu_variant = kUnknown;
155 if (cpu_variant == kUnknown) {
156 cpu_variant = init_cpu_variant();
157 }
158 return cpu_variant;
159}
160
161typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
162DEFINE_IFUNC(memmove) {
Haibo Huang01bfd892018-12-03 15:05:16 -0800163 RETURN_FUNC(memmove_func, memmove_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800164}
165
166typedef void* memcpy_func(void*, const void*, size_t);
167DEFINE_IFUNC(memcpy) {
168 return memmove_resolver();
169}
170
Haibo Huang01bfd892018-12-03 15:05:16 -0800171typedef void* __memcpy_func(void*, const void*, size_t);
172DEFINE_IFUNC(__memcpy) {
173 switch(get_cpu_variant()) {
174 case kCortexA7:
175 RETURN_FUNC(__memcpy_func, __memcpy_a7);
176 case kCortexA9:
177 RETURN_FUNC(__memcpy_func, __memcpy_a9);
178 case kKrait:
179 RETURN_FUNC(__memcpy_func, __memcpy_krait);
180 case kCortexA53:
181 RETURN_FUNC(__memcpy_func, __memcpy_a53);
182 case kCortexA55:
183 RETURN_FUNC(__memcpy_func, __memcpy_a55);
184 case kKryo:
185 RETURN_FUNC(__memcpy_func, __memcpy_kryo);
186 default:
187 RETURN_FUNC(__memcpy_func, __memcpy_a15);
188 }
189}
190
Haibo Huangea9957a2018-11-19 11:00:32 -0800191typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
192DEFINE_IFUNC(__memset_chk) {
193 switch(get_cpu_variant()) {
194 case kCortexA7:
195 case kCortexA53:
196 case kCortexA55:
197 case kKryo:
198 RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
199 case kCortexA9:
200 RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
201 case kKrait:
202 RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800203 default:
204 RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
205 }
206}
207
208typedef void* memset_func(void* __dst, int __ch, size_t __n);
209DEFINE_IFUNC(memset) {
210 switch(get_cpu_variant()) {
211 case kCortexA7:
212 case kCortexA53:
213 case kCortexA55:
214 case kKryo:
215 RETURN_FUNC(memset_func, memset_a7);
216 case kCortexA9:
217 RETURN_FUNC(memset_func, memset_a9);
218 case kKrait:
219 RETURN_FUNC(memset_func, memset_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800220 default:
221 RETURN_FUNC(memset_func, memset_a15);
222 }
223}
224
225typedef char* strcpy_func(char* __dst, const char* __src);
226DEFINE_IFUNC(strcpy) {
227 switch(get_cpu_variant()) {
228 case kCortexA9:
229 RETURN_FUNC(strcpy_func, strcpy_a9);
230 default:
231 RETURN_FUNC(strcpy_func, strcpy_a15);
232 }
233}
234
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800235typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
236DEFINE_IFUNC(__strcpy_chk) {
237 switch(get_cpu_variant()) {
238 case kCortexA7:
239 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
240 case kCortexA9:
241 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
242 case kKrait:
243 case kKryo:
244 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
245 case kCortexA53:
246 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
247 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800248 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800249 default:
250 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
251 }
252}
253
Haibo Huangea9957a2018-11-19 11:00:32 -0800254typedef char* stpcpy_func(char* __dst, const char* __src);
255DEFINE_IFUNC(stpcpy) {
256 switch(get_cpu_variant()) {
257 case kCortexA9:
258 RETURN_FUNC(stpcpy_func, stpcpy_a9);
259 default:
260 RETURN_FUNC(stpcpy_func, stpcpy_a15);
261 }
262}
263
264typedef char* strcat_func(char* __dst, const char* __src);
265DEFINE_IFUNC(strcat) {
266 switch(get_cpu_variant()) {
267 case kCortexA9:
268 RETURN_FUNC(strcat_func, strcat_a9);
269 default:
270 RETURN_FUNC(strcat_func, strcat_a15);
271 }
272}
273
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800274typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
275DEFINE_IFUNC(__strcat_chk) {
276 switch(get_cpu_variant()) {
277 case kCortexA7:
278 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
279 case kCortexA9:
280 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
281 case kKrait:
282 case kKryo:
283 RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
284 case kCortexA53:
285 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
286 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800287 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800288 default:
289 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
290 }
291}
292
Haibo Huangea9957a2018-11-19 11:00:32 -0800293typedef int strcmp_func(const char* __lhs, const char* __rhs);
Haibo Huange4788d42018-12-11 20:28:02 -0800294DEFINE_INTERNAL_IFUNC(strcmp) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800295 switch(get_cpu_variant()) {
296 case kCortexA9:
297 RETURN_FUNC(strcmp_func, strcmp_a9);
298 case kCortexA55:
299 case kKrait:
300 case kKryo:
301 RETURN_FUNC(strcmp_func, strcmp_krait);
302 default:
303 RETURN_FUNC(strcmp_func, strcmp_a15);
304 }
305}
306
307typedef size_t strlen_func(const char* __s);
Haibo Huange4788d42018-12-11 20:28:02 -0800308DEFINE_INTERNAL_IFUNC(strlen) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800309 switch(get_cpu_variant()) {
310 case kCortexA9:
311 RETURN_FUNC(strlen_func, strlen_a9);
312 default:
313 RETURN_FUNC(strlen_func, strlen_a15);
314 }
315}
316
317} // extern "C"