blob: f984421746571304e7e6f5841003a678768c30c6 [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>
Elliott Hughesa4c78762019-09-17 09:53:14 -070030#include <private/bionic_ifuncs.h>
Elliott Hughesadc41712024-08-16 13:08:11 +000031#include <sys/syscall.h>
Elliott Hughesa4c78762019-09-17 09:53:14 -070032
Haibo Huangea9957a2018-11-19 11:00:32 -080033extern "C" {
34
35enum CpuVariant {
Elliott Hughesadc41712024-08-16 13:08:11 +000036 kUnknown = 0,
37 kGeneric,
38 kCortexA7,
39 kCortexA9,
40 kCortexA53,
41 kCortexA55,
42 kKrait,
43 kKryo,
Haibo Huangea9957a2018-11-19 11:00:32 -080044};
45
46static constexpr int MAX_CPU_NAME_LEN = 12;
47struct CpuVariantNames {
Elliott Hughesadc41712024-08-16 13:08:11 +000048 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
49 CpuVariant variant;
Haibo Huangea9957a2018-11-19 11:00:32 -080050};
51
52static constexpr CpuVariantNames cpu_variant_names[] = {
53 {"cortex-a76", kCortexA55},
Haibo Huang4af19612018-12-04 12:54:43 -080054 {"kryo385", kCortexA55},
Haibo Huangea9957a2018-11-19 11:00:32 -080055 {"cortex-a75", kCortexA55},
56 {"kryo", kKryo},
57 {"cortex-a73", kCortexA55},
58 {"cortex-a55", kCortexA55},
59 {"cortex-a53", kCortexA53},
60 {"krait", kKrait},
61 {"cortex-a9", kCortexA9},
62 {"cortex-a7", kCortexA7},
Haibo Huangea9957a2018-11-19 11:00:32 -080063 // kUnknown indicates the end of this array.
64 {"", kUnknown},
65};
66
67static long ifunc_open(const char* pathname) {
Elliott Hughesadc41712024-08-16 13:08:11 +000068 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"
74 : "=r"(r0)
75 : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
76 return r0;
Haibo Huangea9957a2018-11-19 11:00:32 -080077}
78
79static ssize_t ifunc_read(int fd, void* buf, size_t count) {
Elliott Hughesadc41712024-08-16 13:08:11 +000080 register long r0 __asm__("r0") = fd;
81 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
82 register long r2 __asm__("r2") = count;
83 register long r7 __asm__("r7") = __NR_read;
84 __asm__ volatile("swi #0"
85 : "=r"(r0)
86 : "r"(r0), "r"(r1), "r"(r2), "r"(r7)
87 : "memory");
88 return r0;
Haibo Huangea9957a2018-11-19 11:00:32 -080089}
90
91static int ifunc_close(int fd) {
Elliott Hughesadc41712024-08-16 13:08:11 +000092 register long r0 __asm__("r0") = fd;
93 register long r7 __asm__("r7") = __NR_close;
94 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
95 return r0;
Haibo Huangea9957a2018-11-19 11:00:32 -080096}
97
Haibo Huang73ad7902018-11-28 22:56:58 -080098static bool is_same_name(const char* a, const char* b) {
Elliott Hughesadc41712024-08-16 13:08:11 +000099 static_assert(MAX_CPU_NAME_LEN % sizeof(int) == 0, "");
100 const int* ia = reinterpret_cast<const int*>(a);
101 const int* ib = reinterpret_cast<const int*>(b);
102 for (size_t i = 0; i < MAX_CPU_NAME_LEN / sizeof(int); ++i) {
103 if (ia[i] != ib[i]) {
104 return false;
Haibo Huang73ad7902018-11-28 22:56:58 -0800105 }
Elliott Hughesadc41712024-08-16 13:08:11 +0000106 }
107 return true;
Haibo Huang73ad7902018-11-28 22:56:58 -0800108}
109
Haibo Huangea9957a2018-11-19 11:00:32 -0800110static CpuVariant init_cpu_variant() {
Elliott Hughesadc41712024-08-16 13:08:11 +0000111 int fd = ifunc_open("/dev/cpu_variant:arm");
112 if (fd < 0) return kGeneric;
Haibo Huangea9957a2018-11-19 11:00:32 -0800113
Elliott Hughesadc41712024-08-16 13:08:11 +0000114 alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
Haibo Huangea9957a2018-11-19 11:00:32 -0800115
Elliott Hughesadc41712024-08-16 13:08:11 +0000116 int bytes_read, total_read = 0;
117 while (total_read < MAX_CPU_NAME_LEN - 1 &&
118 (bytes_read = ifunc_read(fd, name + total_read,
119 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
120 total_read += bytes_read;
121 }
122 ifunc_close(fd);
Haibo Huangea9957a2018-11-19 11:00:32 -0800123
Elliott Hughesadc41712024-08-16 13:08:11 +0000124 if (bytes_read != 0) {
125 // The file is too big. We haven't reach the end. Or maybe there is an
126 // error when reading.
Haibo Huangea9957a2018-11-19 11:00:32 -0800127 return kGeneric;
Elliott Hughesadc41712024-08-16 13:08:11 +0000128 }
129 name[total_read] = 0;
130
131 const CpuVariantNames* cpu_variant = cpu_variant_names;
132 while (cpu_variant->variant != kUnknown) {
133 if (is_same_name(cpu_variant->name, name)) {
134 return cpu_variant->variant;
135 }
136 cpu_variant++;
137 }
138 return kGeneric;
Haibo Huangea9957a2018-11-19 11:00:32 -0800139}
140
141static CpuVariant get_cpu_variant() {
Elliott Hughesadc41712024-08-16 13:08:11 +0000142 static CpuVariant cpu_variant = kUnknown;
143 if (cpu_variant == kUnknown) {
144 cpu_variant = init_cpu_variant();
145 }
146 return cpu_variant;
Haibo Huangea9957a2018-11-19 11:00:32 -0800147}
148
Elliott Hughesa4c78762019-09-17 09:53:14 -0700149DEFINE_IFUNC_FOR(memmove) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000150 RETURN_FUNC(memmove_func_t, memmove_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800151}
Elliott Hughesadc41712024-08-16 13:08:11 +0000152MEMMOVE_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800153
Elliott Hughesa4c78762019-09-17 09:53:14 -0700154DEFINE_IFUNC_FOR(memcpy) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000155 return memmove_resolver(hwcap);
Haibo Huangea9957a2018-11-19 11:00:32 -0800156}
Elliott Hughesadc41712024-08-16 13:08:11 +0000157MEMCPY_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800158
Elliott Hughesadc41712024-08-16 13:08:11 +0000159// On arm32, __memcpy() is not publicly exposed, but gets called by memmove()
160// in cases where the copy is known to be overlap-safe.
161typedef void* __memcpy_func_t(void*, const void*, size_t);
Elliott Hughesa4c78762019-09-17 09:53:14 -0700162DEFINE_IFUNC_FOR(__memcpy) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000163 switch (get_cpu_variant()) {
164 case kCortexA7:
165 RETURN_FUNC(__memcpy_func_t, __memcpy_a7);
166 case kCortexA9:
167 RETURN_FUNC(__memcpy_func_t, __memcpy_a9);
168 case kKrait:
169 RETURN_FUNC(__memcpy_func_t, __memcpy_krait);
170 case kCortexA53:
171 RETURN_FUNC(__memcpy_func_t, __memcpy_a53);
172 case kCortexA55:
173 RETURN_FUNC(__memcpy_func_t, __memcpy_a55);
174 case kKryo:
175 RETURN_FUNC(__memcpy_func_t, __memcpy_kryo);
176 default:
177 RETURN_FUNC(__memcpy_func_t, __memcpy_a15);
178 }
Haibo Huang01bfd892018-12-03 15:05:16 -0800179}
Elliott Hughesadc41712024-08-16 13:08:11 +0000180DEFINE_STATIC_SHIM(void* __memcpy(void* dst, const void* src, size_t n) {
181 FORWARD(__memcpy)(dst, src, n);
182})
Haibo Huang01bfd892018-12-03 15:05:16 -0800183
Elliott Hughesa4c78762019-09-17 09:53:14 -0700184DEFINE_IFUNC_FOR(__memset_chk) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000185 switch (get_cpu_variant()) {
186 case kCortexA7:
187 case kCortexA53:
188 case kCortexA55:
189 case kKryo:
190 RETURN_FUNC(__memset_chk_func_t, __memset_chk_a7);
191 case kCortexA9:
192 RETURN_FUNC(__memset_chk_func_t, __memset_chk_a9);
193 case kKrait:
194 RETURN_FUNC(__memset_chk_func_t, __memset_chk_krait);
195 default:
196 RETURN_FUNC(__memset_chk_func_t, __memset_chk_a15);
197 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800198}
Elliott Hughesadc41712024-08-16 13:08:11 +0000199__MEMSET_CHK_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800200
Elliott Hughesa4c78762019-09-17 09:53:14 -0700201DEFINE_IFUNC_FOR(memset) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000202 switch (get_cpu_variant()) {
203 case kCortexA7:
204 case kCortexA53:
205 case kCortexA55:
206 case kKryo:
207 RETURN_FUNC(memset_func_t, memset_a7);
208 case kCortexA9:
209 RETURN_FUNC(memset_func_t, memset_a9);
210 case kKrait:
211 RETURN_FUNC(memset_func_t, memset_krait);
212 default:
213 RETURN_FUNC(memset_func_t, memset_a15);
214 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800215}
Elliott Hughesadc41712024-08-16 13:08:11 +0000216MEMSET_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800217
Elliott Hughesa4c78762019-09-17 09:53:14 -0700218DEFINE_IFUNC_FOR(strcpy) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000219 switch (get_cpu_variant()) {
220 case kCortexA9:
221 RETURN_FUNC(strcpy_func_t, strcpy_a9);
222 default:
223 RETURN_FUNC(strcpy_func_t, strcpy_a15);
224 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800225}
Elliott Hughesadc41712024-08-16 13:08:11 +0000226STRCPY_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800227
Elliott Hughesa4c78762019-09-17 09:53:14 -0700228DEFINE_IFUNC_FOR(__strcpy_chk) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000229 switch (get_cpu_variant()) {
230 case kCortexA7:
231 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a7);
232 case kCortexA9:
233 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a9);
234 case kKrait:
235 case kKryo:
236 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_krait);
237 case kCortexA53:
238 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a53);
239 case kCortexA55:
240 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a55);
241 default:
242 RETURN_FUNC(__strcpy_chk_func_t, __strcpy_chk_a15);
243 }
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800244}
Elliott Hughesadc41712024-08-16 13:08:11 +0000245__STRCPY_CHK_SHIM()
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800246
Elliott Hughesa4c78762019-09-17 09:53:14 -0700247DEFINE_IFUNC_FOR(stpcpy) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000248 switch (get_cpu_variant()) {
249 case kCortexA9:
250 RETURN_FUNC(stpcpy_func_t, stpcpy_a9);
251 default:
252 RETURN_FUNC(stpcpy_func_t, stpcpy_a15);
253 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800254}
Elliott Hughesadc41712024-08-16 13:08:11 +0000255STPCPY_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800256
Elliott Hughesa4c78762019-09-17 09:53:14 -0700257DEFINE_IFUNC_FOR(strcat) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000258 switch (get_cpu_variant()) {
259 case kCortexA9:
260 RETURN_FUNC(strcat_func_t, strcat_a9);
261 default:
262 RETURN_FUNC(strcat_func_t, strcat_a15);
263 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800264}
Elliott Hughesadc41712024-08-16 13:08:11 +0000265STRCAT_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800266
Elliott Hughesa4c78762019-09-17 09:53:14 -0700267DEFINE_IFUNC_FOR(__strcat_chk) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000268 switch (get_cpu_variant()) {
269 case kCortexA7:
270 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a7);
271 case kCortexA9:
272 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a9);
273 case kKrait:
274 case kKryo:
275 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_krait);
276 case kCortexA53:
277 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a53);
278 case kCortexA55:
279 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a55);
280 default:
281 RETURN_FUNC(__strcat_chk_func_t, __strcat_chk_a15);
282 }
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800283}
Elliott Hughesadc41712024-08-16 13:08:11 +0000284__STRCAT_CHK_SHIM()
Haibo Huangf1c8d1a2018-11-27 15:38:47 -0800285
Elliott Hughesa4c78762019-09-17 09:53:14 -0700286DEFINE_IFUNC_FOR(strcmp) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000287 RETURN_FUNC(strcmp_func_t, strcmp_a15);
Haibo Huangea9957a2018-11-19 11:00:32 -0800288}
Elliott Hughesadc41712024-08-16 13:08:11 +0000289STRCMP_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800290
Elliott Hughesa4c78762019-09-17 09:53:14 -0700291DEFINE_IFUNC_FOR(strlen) {
Elliott Hughesadc41712024-08-16 13:08:11 +0000292 switch (get_cpu_variant()) {
293 case kCortexA9:
294 RETURN_FUNC(strlen_func_t, strlen_a9);
295 default:
296 RETURN_FUNC(strlen_func_t, strlen_a15);
297 }
Haibo Huangea9957a2018-11-19 11:00:32 -0800298}
Elliott Hughesadc41712024-08-16 13:08:11 +0000299STRLEN_SHIM()
Haibo Huangea9957a2018-11-19 11:00:32 -0800300
301} // extern "C"