• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
32 extern "C" {
33 
34 enum CpuVariant {
35     kUnknown = 0,
36     kGeneric,
37     kCortexA7,
38     kCortexA9,
39     kCortexA53,
40     kCortexA55,
41     kKrait,
42     kKryo,
43 };
44 
45 static constexpr int MAX_CPU_NAME_LEN = 12;
46 struct CpuVariantNames {
47     alignas(alignof(int)) char name[MAX_CPU_NAME_LEN];
48     CpuVariant variant;
49 };
50 
51 static constexpr CpuVariantNames cpu_variant_names[] = {
52     {"cortex-a76", kCortexA55},
53     {"kryo385", 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     // kUnknown indicates the end of this array.
63     {"", kUnknown},
64 };
65 
ifunc_open(const char * pathname)66 static 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 
ifunc_read(int fd,void * buf,size_t count)76 static 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 
ifunc_close(int fd)85 static 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 
is_same_name(const char * a,const char * b)106 static 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 
init_cpu_variant()118 static CpuVariant init_cpu_variant() {
119     int fd = ifunc_open("/dev/cpu_variant:arm");
120     if (fd < 0) return kGeneric;
121 
122     alignas(alignof(int)) char name[MAX_CPU_NAME_LEN] = {};
123 
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 
139     const CpuVariantNames* cpu_variant = cpu_variant_names;
140     while (cpu_variant->variant != kUnknown) {
141         if (is_same_name(cpu_variant->name, name)) {
142             return cpu_variant->variant;
143         }
144         cpu_variant++;
145     }
146     return kGeneric;
147 }
148 
get_cpu_variant()149 static 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 
157 typedef void* memmove_func(void* __dst, const void* __src, size_t __n);
DEFINE_IFUNC(memmove)158 DEFINE_IFUNC(memmove) {
159     RETURN_FUNC(memmove_func, memmove_a15);
160 }
161 
162 typedef void* memcpy_func(void*, const void*, size_t);
DEFINE_IFUNC(memcpy)163 DEFINE_IFUNC(memcpy) {
164     return memmove_resolver();
165 }
166 
167 typedef void* __memcpy_func(void*, const void*, size_t);
DEFINE_IFUNC(__memcpy)168 DEFINE_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 
187 typedef void* __memset_chk_func(void* s, int c, size_t n, size_t n2);
DEFINE_IFUNC(__memset_chk)188 DEFINE_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);
199         default:
200             RETURN_FUNC(__memset_chk_func, __memset_chk_a15);
201     }
202 }
203 
204 typedef void* memset_func(void* __dst, int __ch, size_t __n);
DEFINE_IFUNC(memset)205 DEFINE_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);
216         default:
217              RETURN_FUNC(memset_func, memset_a15);
218     }
219 }
220 
221 typedef char* strcpy_func(char* __dst, const char* __src);
DEFINE_IFUNC(strcpy)222 DEFINE_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 
231 typedef char* __strcpy_chk_func(char* dst, const char* src, size_t dst_len);
DEFINE_IFUNC(__strcpy_chk)232 DEFINE_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:
244             RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a55);
245         default:
246             RETURN_FUNC(__strcpy_chk_func, __strcpy_chk_a15);
247     }
248 }
249 
250 typedef char* stpcpy_func(char* __dst, const char* __src);
DEFINE_IFUNC(stpcpy)251 DEFINE_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 
260 typedef char* strcat_func(char* __dst, const char* __src);
DEFINE_IFUNC(strcat)261 DEFINE_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 
270 typedef char* __strcat_chk_func(char* dst, const char* src, size_t dst_buf_size);
DEFINE_IFUNC(__strcat_chk)271 DEFINE_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:
283             RETURN_FUNC(__strcat_chk_func, __strcat_chk_a55);
284         default:
285             RETURN_FUNC(__strcat_chk_func, __strcat_chk_a15);
286     }
287 }
288 
289 typedef int strcmp_func(const char* __lhs, const char* __rhs);
DEFINE_IFUNC(strcmp)290 DEFINE_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 
303 typedef size_t strlen_func(const char* __s);
DEFINE_IFUNC(strlen)304 DEFINE_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"
314