blob: 17f00876be7b71d5500810c4e24819b23513a9d0 [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,
41 kDenver,
42 kKrait,
43 kKryo,
44};
45
46static constexpr int MAX_CPU_NAME_LEN = 12;
47struct CpuVariantNames {
48 char name[MAX_CPU_NAME_LEN];
49 CpuVariant variant;
50};
51
52static constexpr CpuVariantNames cpu_variant_names[] = {
53 {"cortex-a76", kCortexA55},
54 {"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},
62 {"denver", kDenver},
63 // kUnknown indicates the end of this array.
64 {"", kUnknown},
65};
66
67static long ifunc_open(const char* pathname) {
68 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" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r7));
74 return r0;
75}
76
77static ssize_t ifunc_read(int fd, void* buf, size_t count) {
78 register long r0 __asm__("r0") = fd;
79 register long r1 __asm__("r1") = reinterpret_cast<long>(buf);
80 register long r2 __asm__("r2") = count;
81 register long r7 __asm__("r7") = __NR_read;
82 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r7) : "memory");
83 return r0;
84}
85
86static int ifunc_close(int fd) {
87 register long r0 __asm__("r0") = fd;
88 register long r7 __asm__("r7") = __NR_close;
89 __asm__ volatile("swi #0" : "=r"(r0) : "r"(r0), "r"(r7));
90 return r0;
91}
92
93#define DEFINE_IFUNC(name) \
94 name##_func name __attribute__((ifunc(#name "_resolver"))); \
95 __attribute__((visibility("hidden"))) \
96 name##_func* name##_resolver()
97
98#define DECLARE_FUNC(type, name) \
99 __attribute__((visibility("hidden"))) \
100 type name
101
102#define RETURN_FUNC(type, name) { \
103 DECLARE_FUNC(type, name); \
104 return name; \
105 }
106
107static CpuVariant init_cpu_variant() {
108 int fd = ifunc_open("/dev/cpu_variant:arm");
109 if (fd < 0) return kGeneric;
110
111 char name[MAX_CPU_NAME_LEN];
112
113 int bytes_read, total_read = 0;
114 while (total_read < MAX_CPU_NAME_LEN - 1 &&
115 (bytes_read = ifunc_read(fd, name + total_read,
116 MAX_CPU_NAME_LEN - 1 - total_read)) > 0) {
117 total_read += bytes_read;
118 }
119 ifunc_close(fd);
120
121 if (bytes_read != 0) {
122 // The file is too big. We haven't reach the end. Or maybe there is an
123 // error when reading.
124 return kGeneric;
125 }
126 name[total_read] = 0;
127
128 typedef int strcmp_func(const char* __lhs, const char* __rhs);
129 DECLARE_FUNC(strcmp_func, strcmp_a15);
130
131 const CpuVariantNames* cpu_variant = cpu_variant_names;
132 while (cpu_variant->variant != kUnknown) {
133 if (strcmp_a15(cpu_variant->name, name) == 0) {
134 return cpu_variant->variant;
135 }
136 cpu_variant++;
137 }
138 return kGeneric;
139}
140
141static CpuVariant get_cpu_variant() {
142 static CpuVariant cpu_variant = kUnknown;
143 if (cpu_variant == kUnknown) {
144 cpu_variant = init_cpu_variant();
145 }
146 return cpu_variant;
147}
148
149typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
150DEFINE_IFUNC(memmove) {
151 switch(get_cpu_variant()) {
152 case kCortexA7:
153 RETURN_FUNC(memmove_func, memmove_a7);
154 case kCortexA9:
155 RETURN_FUNC(memmove_func, memmove_a9);
156 case kKrait:
157 RETURN_FUNC(memmove_func, memmove_krait);
158 case kCortexA53:
159 RETURN_FUNC(memmove_func, memmove_a53);
160 case kCortexA55:
161 case kDenver:
162 RETURN_FUNC(memmove_func, memmove_denver);
163 case kKryo:
164 RETURN_FUNC(memmove_func, memmove_kryo);
165 default:
166 RETURN_FUNC(memmove_func, memmove_a15);
167 }
168}
169
170typedef void* memcpy_func(void*, const void*, size_t);
171DEFINE_IFUNC(memcpy) {
172 return memmove_resolver();
173}
174
175typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
176DEFINE_IFUNC(__memset_chk) {
177 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);
187 case kDenver:
188 RETURN_FUNC(__memset_chk_func, __memset_chk_denver);
189 default:
190 RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
191 }
192}
193
194typedef void* memset_func(void* __dst, int __ch, size_t __n);
195DEFINE_IFUNC(memset) {
196 switch(get_cpu_variant()) {
197 case kCortexA7:
198 case kCortexA53:
199 case kCortexA55:
200 case kKryo:
201 RETURN_FUNC(memset_func, memset_a7);
202 case kCortexA9:
203 RETURN_FUNC(memset_func, memset_a9);
204 case kKrait:
205 RETURN_FUNC(memset_func, memset_krait);
206 case kDenver:
207 RETURN_FUNC(memset_func, memset_denver);
208 default:
209 RETURN_FUNC(memset_func, memset_a15);
210 }
211}
212
213typedef char* strcpy_func(char* __dst, const char* __src);
214DEFINE_IFUNC(strcpy) {
215 switch(get_cpu_variant()) {
216 case kCortexA9:
217 RETURN_FUNC(strcpy_func, strcpy_a9);
218 default:
219 RETURN_FUNC(strcpy_func, strcpy_a15);
220 }
221}
222
223typedef char* stpcpy_func(char* __dst, const char* __src);
224DEFINE_IFUNC(stpcpy) {
225 switch(get_cpu_variant()) {
226 case kCortexA9:
227 RETURN_FUNC(stpcpy_func, stpcpy_a9);
228 default:
229 RETURN_FUNC(stpcpy_func, stpcpy_a15);
230 }
231}
232
233typedef char* strcat_func(char* __dst, const char* __src);
234DEFINE_IFUNC(strcat) {
235 switch(get_cpu_variant()) {
236 case kCortexA9:
237 RETURN_FUNC(strcat_func, strcat_a9);
238 default:
239 RETURN_FUNC(strcat_func, strcat_a15);
240 }
241}
242
243typedef int strcmp_func(const char* __lhs, const char* __rhs);
244DEFINE_IFUNC(strcmp) {
245 switch(get_cpu_variant()) {
246 case kCortexA9:
247 RETURN_FUNC(strcmp_func, strcmp_a9);
248 case kCortexA55:
249 case kKrait:
250 case kKryo:
251 RETURN_FUNC(strcmp_func, strcmp_krait);
252 default:
253 RETURN_FUNC(strcmp_func, strcmp_a15);
254 }
255}
256
257typedef size_t strlen_func(const char* __s);
258DEFINE_IFUNC(strlen) {
259 switch(get_cpu_variant()) {
260 case kCortexA9:
261 RETURN_FUNC(strlen_func, strlen_a9);
262 default:
263 RETURN_FUNC(strlen_func, strlen_a15);
264 }
265}
266
267} // extern "C"