blob: 640f3306a81c5bee059aa4010b0e50add8a8238f [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
92#define DEFINE_IFUNC(name) \
93 name##_func name __attribute__((ifunc(#name "_resolver"))); \
94 __attribute__((visibility("hidden"))) \
95 name##_func* name##_resolver()
96
97#define DECLARE_FUNC(type, name) \
98 __attribute__((visibility("hidden"))) \
99 type name
100
101#define RETURN_FUNC(type, name) { \
102 DECLARE_FUNC(type, name); \
103 return name; \
104 }
105
Haibo Huang73ad7902018-11-28 22:56:58 -0800106static bool is_same_name(const char* a, const char* b) {
107 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
108 const int* ia = reinterpret_cast<const int*>(a);
109 const int* ib = reinterpret_cast<const int*>(b);
110 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
111 if (ia[i] != ib[i]) {
112 return false;
113 }
114 }
115 return true;
116}
117
Haibo Huangea9957a2018-11-19 11:00:32 -0800118static CpuVariant init_cpu_variant() {
119 int fd = ifunc_open("/dev/cpu_variant:arm");
120 if (fd < 0) return kGeneric;
121
Haibo Huang73ad7902018-11-28 22:56:58 -0800122 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800123
124 int bytes_read, total_read = 0;
125 while (total_read < MAX_CPU_NAME_LEN - 1 &&
126 (bytes_read = ifunc_read(fd, name + total_read,
127 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
128 total_read += bytes_read;
129 }
130 ifunc_close(fd);
131
132 if (bytes_read != 0) {
133 // The file is too big. We haven't reach the end. Or maybe there is an
134 // error when reading.
135 return kGeneric;
136 }
137 name[total_read] = 0;
138
Haibo Huangea9957a2018-11-19 11:00:32 -0800139 const CpuVariantNames* cpu_variant = cpu_variant_names;
140 while (cpu_variant->variant != kUnknown) {
Haibo Huang73ad7902018-11-28 22:56:58 -0800141 if (is_same_name(cpu_variant->name, name)) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800142 return cpu_variant->variant;
143 }
144 cpu_variant++;
145 }
146 return kGeneric;
147}
148
149static CpuVariant get_cpu_variant() {
150 static CpuVariant cpu_variant = kUnknown;
151 if (cpu_variant == kUnknown) {
152 cpu_variant = init_cpu_variant();
153 }
154 return cpu_variant;
155}
156
157typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
158DEFINE_IFUNC(memmove) {
Haibo Huang01bfd892018-12-03 15:05:16 -0800159 RETURN_FUNC(memmove_func, memmove_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800160}
161
162typedef void* memcpy_func(void*, const void*, size_t);
163DEFINE_IFUNC(memcpy) {
164 return memmove_resolver();
165}
166
Haibo Huang01bfd892018-12-03 15:05:16 -0800167typedef void* __memcpy_func(void*, const void*, size_t);
168DEFINE_IFUNC(__memcpy) {
169 switch(get_cpu_variant()) {
170 case kCortexA7:
171 RETURN_FUNC(__memcpy_func, __memcpy_a7);
172 case kCortexA9:
173 RETURN_FUNC(__memcpy_func, __memcpy_a9);
174 case kKrait:
175 RETURN_FUNC(__memcpy_func, __memcpy_krait);
176 case kCortexA53:
177 RETURN_FUNC(__memcpy_func, __memcpy_a53);
178 case kCortexA55:
179 RETURN_FUNC(__memcpy_func, __memcpy_a55);
180 case kKryo:
181 RETURN_FUNC(__memcpy_func, __memcpy_kryo);
182 default:
183 RETURN_FUNC(__memcpy_func, __memcpy_a15);
184 }
185}
186
Haibo Huangea9957a2018-11-19 11:00:32 -0800187typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
188DEFINE_IFUNC(__memset_chk) {
189 switch(get_cpu_variant()) {
190 case kCortexA7:
191 case kCortexA53:
192 case kCortexA55:
193 case kKryo:
194 RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
195 case kCortexA9:
196 RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
197 case kKrait:
198 RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800199 default:
200 RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
201 }
202}
203
204typedef void* memset_func(void* __dst, int __ch, size_t __n);
205DEFINE_IFUNC(memset) {
206 switch(get_cpu_variant()) {
207 case kCortexA7:
208 case kCortexA53:
209 case kCortexA55:
210 case kKryo:
211 RETURN_FUNC(memset_func, memset_a7);
212 case kCortexA9:
213 RETURN_FUNC(memset_func, memset_a9);
214 case kKrait:
215 RETURN_FUNC(memset_func, memset_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800216 default:
217 RETURN_FUNC(memset_func, memset_a15);
218 }
219}
220
221typedef char* strcpy_func(char* __dst, const char* __src);
222DEFINE_IFUNC(strcpy) {
223 switch(get_cpu_variant()) {
224 case kCortexA9:
225 RETURN_FUNC(strcpy_func, strcpy_a9);
226 default:
227 RETURN_FUNC(strcpy_func, strcpy_a15);
228 }
229}
230
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800231typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
232DEFINE_IFUNC(__strcpy_chk) {
233 switch(get_cpu_variant()) {
234 case kCortexA7:
235 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
236 case kCortexA9:
237 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
238 case kKrait:
239 case kKryo:
240 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
241 case kCortexA53:
242 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
243 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800244 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800245 default:
246 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
247 }
248}
249
Haibo Huangea9957a2018-11-19 11:00:32 -0800250typedef char* stpcpy_func(char* __dst, const char* __src);
251DEFINE_IFUNC(stpcpy) {
252 switch(get_cpu_variant()) {
253 case kCortexA9:
254 RETURN_FUNC(stpcpy_func, stpcpy_a9);
255 default:
256 RETURN_FUNC(stpcpy_func, stpcpy_a15);
257 }
258}
259
260typedef char* strcat_func(char* __dst, const char* __src);
261DEFINE_IFUNC(strcat) {
262 switch(get_cpu_variant()) {
263 case kCortexA9:
264 RETURN_FUNC(strcat_func, strcat_a9);
265 default:
266 RETURN_FUNC(strcat_func, strcat_a15);
267 }
268}
269
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800270typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
271DEFINE_IFUNC(__strcat_chk) {
272 switch(get_cpu_variant()) {
273 case kCortexA7:
274 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
275 case kCortexA9:
276 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
277 case kKrait:
278 case kKryo:
279 RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
280 case kCortexA53:
281 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
282 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800283 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800284 default:
285 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
286 }
287}
288
Haibo Huangea9957a2018-11-19 11:00:32 -0800289typedef int strcmp_func(const char* __lhs, const char* __rhs);
290DEFINE_IFUNC(strcmp) {
291 switch(get_cpu_variant()) {
292 case kCortexA9:
293 RETURN_FUNC(strcmp_func, strcmp_a9);
294 case kCortexA55:
295 case kKrait:
296 case kKryo:
297 RETURN_FUNC(strcmp_func, strcmp_krait);
298 default:
299 RETURN_FUNC(strcmp_func, strcmp_a15);
300 }
301}
302
303typedef size_t strlen_func(const char* __s);
304DEFINE_IFUNC(strlen) {
305 switch(get_cpu_variant()) {
306 case kCortexA9:
307 RETURN_FUNC(strlen_func, strlen_a9);
308 default:
309 RETURN_FUNC(strlen_func, strlen_a15);
310 }
311}
312
313} // extern "C"