blob: 1d2f38ff5fe31cee9356fa2111a9d98661d13a1a [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
Elliott Hughesa4c78762019-09-17 09:53:14 -070032#include <private/bionic_ifuncs.h>
33
Haibo Huangea9957a2018-11-19 11:00:32 -080034extern "C" {
35
36enum CpuVariant {
37 kUnknown = 0,
38 kGeneric,
39 kCortexA7,
40 kCortexA9,
41 kCortexA53,
42 kCortexA55,
Haibo Huangea9957a2018-11-19 11:00:32 -080043 kKrait,
44 kKryo,
45};
46
47static constexpr int MAX_CPU_NAME_LEN = 12;
48struct CpuVariantNames {
Haibo Huang73ad7902018-11-28 22:56:58 -080049 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
Haibo Huangea9957a2018-11-19 11:00:32 -080050 CpuVariant variant;
51};
52
53static constexpr CpuVariantNames cpu_variant_names[] = {
54 {"cortex-a76", kCortexA55},
Haibo Huang4af19612018-12-04 12:54:43 -080055 {"kryo385", kCortexA55},
Haibo Huangea9957a2018-11-19 11:00:32 -080056 {"cortex-a75", kCortexA55},
57 {"kryo", kKryo},
58 {"cortex-a73", kCortexA55},
59 {"cortex-a55", kCortexA55},
60 {"cortex-a53", kCortexA53},
61 {"krait", kKrait},
62 {"cortex-a9", kCortexA9},
63 {"cortex-a7", kCortexA7},
Haibo Huangea9957a2018-11-19 11:00:32 -080064 // kUnknown indicates the end of this array.
65 {"", kUnknown},
66};
67
68static long ifunc_open(const char* pathname) {
69 register long r0 __asm__("r0") = AT_FDCWD;
70 register long r1 __asm__("r1") = reinterpret_cast<long>(pathname);
71 register long r2 __asm__("r2") = O_RDONLY;
72 register long r3 __asm__("r3") = 0;
73 register long r7 __asm__("r7") = __NR_openat;
74 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
75 return r0;
76}
77
78static ssize_t ifunc_read(int fd, void* buf, size_t count) {
79 register long r0 __asm__("r0") = fd;
80 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
81 register long r2 __asm__("r2") = count;
82 register long r7 __asm__("r7") = __NR_read;
83 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
84 return r0;
85}
86
87static int ifunc_close(int fd) {
88 register long r0 __asm__("r0") = fd;
89 register long r7 __asm__("r7") = __NR_close;
90 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
91 return r0;
92}
93
Haibo Huang73ad7902018-11-28 22:56:58 -080094static bool is_same_name(const char* a, const char* b) {
95 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
96 const int* ia = reinterpret_cast<const int*>(a);
97 const int* ib = reinterpret_cast<const int*>(b);
98 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
99 if (ia[i] != ib[i]) {
100 return false;
101 }
102 }
103 return true;
104}
105
Haibo Huangea9957a2018-11-19 11:00:32 -0800106static CpuVariant init_cpu_variant() {
107 int fd = ifunc_open("/dev/cpu_variant:arm");
108 if (fd < 0) return kGeneric;
109
Haibo Huang73ad7902018-11-28 22:56:58 -0800110 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800111
112 int bytes_read, total_read = 0;
113 while (total_read < MAX_CPU_NAME_LEN - 1 &&
114 (bytes_read = ifunc_read(fd, name + total_read,
115 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
116 total_read += bytes_read;
117 }
118 ifunc_close(fd);
119
120 if (bytes_read != 0) {
121 // The file is too big. We haven't reach the end. Or maybe there is an
122 // error when reading.
123 return kGeneric;
124 }
125 name[total_read] = 0;
126
Haibo Huangea9957a2018-11-19 11:00:32 -0800127 const CpuVariantNames* cpu_variant = cpu_variant_names;
128 while (cpu_variant->variant != kUnknown) {
Haibo Huang73ad7902018-11-28 22:56:58 -0800129 if (is_same_name(cpu_variant->name, name)) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800130 return cpu_variant->variant;
131 }
132 cpu_variant++;
133 }
134 return kGeneric;
135}
136
137static CpuVariant get_cpu_variant() {
138 static CpuVariant cpu_variant = kUnknown;
139 if (cpu_variant == kUnknown) {
140 cpu_variant = init_cpu_variant();
141 }
142 return cpu_variant;
143}
144
145typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700146DEFINE_IFUNC_FOR(memmove) {
Haibo Huang01bfd892018-12-03 15:05:16 -0800147 RETURN_FUNC(memmove_func, memmove_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800148}
149
150typedef void* memcpy_func(void*, const void*, size_t);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700151DEFINE_IFUNC_FOR(memcpy) {
Peter Collingbourne900d07d2019-10-28 13:11:00 -0700152 return memmove_resolver(hwcap);
Haibo Huangea9957a2018-11-19 11:00:32 -0800153}
154
Haibo Huang01bfd892018-12-03 15:05:16 -0800155typedef void* __memcpy_func(void*, const void*, size_t);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700156DEFINE_IFUNC_FOR(__memcpy) {
Haibo Huang01bfd892018-12-03 15:05:16 -0800157 switch(get_cpu_variant()) {
158 case kCortexA7:
159 RETURN_FUNC(__memcpy_func, __memcpy_a7);
160 case kCortexA9:
161 RETURN_FUNC(__memcpy_func, __memcpy_a9);
162 case kKrait:
163 RETURN_FUNC(__memcpy_func, __memcpy_krait);
164 case kCortexA53:
165 RETURN_FUNC(__memcpy_func, __memcpy_a53);
166 case kCortexA55:
167 RETURN_FUNC(__memcpy_func, __memcpy_a55);
168 case kKryo:
169 RETURN_FUNC(__memcpy_func, __memcpy_kryo);
170 default:
171 RETURN_FUNC(__memcpy_func, __memcpy_a15);
172 }
173}
174
Haibo Huangea9957a2018-11-19 11:00:32 -0800175typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700176DEFINE_IFUNC_FOR(__memset_chk) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800177 switch(get_cpu_variant()) {
178 case kCortexA7:
179 case kCortexA53:
180 case kCortexA55:
181 case kKryo:
182 RETURN_FUNC(__memset_chk_func, __memset_chk_a7);
183 case kCortexA9:
184 RETURN_FUNC(__memset_chk_func, __memset_chk_a9);
185 case kKrait:
186 RETURN_FUNC(__memset_chk_func, __memset_chk_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800187 default:
188 RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
189 }
190}
191
192typedef void* memset_func(void* __dst, int __ch, size_t __n);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700193DEFINE_IFUNC_FOR(memset) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800194 switch(get_cpu_variant()) {
195 case kCortexA7:
196 case kCortexA53:
197 case kCortexA55:
198 case kKryo:
199 RETURN_FUNC(memset_func, memset_a7);
200 case kCortexA9:
201 RETURN_FUNC(memset_func, memset_a9);
202 case kKrait:
203 RETURN_FUNC(memset_func, memset_krait);
Haibo Huangea9957a2018-11-19 11:00:32 -0800204 default:
205 RETURN_FUNC(memset_func, memset_a15);
206 }
207}
208
209typedef char* strcpy_func(char* __dst, const char* __src);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700210DEFINE_IFUNC_FOR(strcpy) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800211 switch(get_cpu_variant()) {
212 case kCortexA9:
213 RETURN_FUNC(strcpy_func, strcpy_a9);
214 default:
215 RETURN_FUNC(strcpy_func, strcpy_a15);
216 }
217}
218
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800219typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700220DEFINE_IFUNC_FOR(__strcpy_chk) {
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800221 switch(get_cpu_variant()) {
222 case kCortexA7:
223 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a7);
224 case kCortexA9:
225 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a9);
226 case kKrait:
227 case kKryo:
228 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_krait);
229 case kCortexA53:
230 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a53);
231 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800232 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800233 default:
234 RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
235 }
236}
237
Haibo Huangea9957a2018-11-19 11:00:32 -0800238typedef char* stpcpy_func(char* __dst, const char* __src);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700239DEFINE_IFUNC_FOR(stpcpy) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800240 switch(get_cpu_variant()) {
241 case kCortexA9:
242 RETURN_FUNC(stpcpy_func, stpcpy_a9);
243 default:
244 RETURN_FUNC(stpcpy_func, stpcpy_a15);
245 }
246}
247
248typedef char* strcat_func(char* __dst, const char* __src);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700249DEFINE_IFUNC_FOR(strcat) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800250 switch(get_cpu_variant()) {
251 case kCortexA9:
252 RETURN_FUNC(strcat_func, strcat_a9);
253 default:
254 RETURN_FUNC(strcat_func, strcat_a15);
255 }
256}
257
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800258typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700259DEFINE_IFUNC_FOR(__strcat_chk) {
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800260 switch(get_cpu_variant()) {
261 case kCortexA7:
262 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a7);
263 case kCortexA9:
264 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a9);
265 case kKrait:
266 case kKryo:
267 RETURN_FUNC(__strcat_chk_func, __strcat_chk_krait);
268 case kCortexA53:
269 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a53);
270 case kCortexA55:
Haibo Huang01bfd892018-12-03 15:05:16 -0800271 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55);
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800272 default:
273 RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
274 }
275}
276
Haibo Huangea9957a2018-11-19 11:00:32 -0800277typedef int strcmp_func(const char* __lhs, const char* __rhs);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700278DEFINE_IFUNC_FOR(strcmp) {
Jake Weinsteinbff53b22017-05-06 23:22:58 -0400279 RETURN_FUNC(strcmp_func, strcmp_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800280}
281
282typedef size_t strlen_func(const char* __s);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700283DEFINE_IFUNC_FOR(strlen) {
Haibo Huangea9957a2018-11-19 11:00:32 -0800284 switch(get_cpu_variant()) {
285 case kCortexA9:
286 RETURN_FUNC(strlen_func, strlen_a9);
287 default:
288 RETURN_FUNC(strlen_func, strlen_a15);
289 }
290}
291
292} // extern "C"