1 /* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
2  *
3  *                     The LLVM Compiler Infrastructure
4  *
5  * This file is dual licensed under the MIT and the University of Illinois Open
6  * Source Licenses. See LICENSE.TXT for details.
7  *
8  * ===----------------------------------------------------------------------===
9  */
10 
11 #include "int_lib.h"
12 
13 #if __APPLE__
14   #include <libkern/OSCacheControl.h>
15 #endif
16 #if defined(__FreeBSD__) && defined(__arm__)
17   #include <sys/types.h>
18   #include <machine/sysarch.h>
19 #endif
20 
21 #if defined(__NetBSD__) && defined(__arm__)
22   #include <machine/sysarch.h>
23 #endif
24 
25 #if defined(__ANDROID__) && defined(__mips__)
26   #include <sys/cachectl.h>
27 #endif
28 
29 #if defined(__ANDROID__) && defined(__arm__)
30   #include <asm/unistd.h>
31 #endif
32 
33 /*
34  * The compiler generates calls to __clear_cache() when creating
35  * trampoline functions on the stack for use with nested functions.
36  * It is expected to invalidate the instruction cache for the
37  * specified range.
38  */
39 
40 void __clear_cache(void *start, void *end) {
41 #if __i386__ || __x86_64__
42 /*
43  * Intel processors have a unified instruction and data cache
44  * so there is nothing to do
45  */
46 #elif defined(__arm__) && !defined(__APPLE__)
47     #if defined(__FreeBSD__) || defined(__NetBSD__)
48         struct arm_sync_icache_args arg;
49 
50         arg.addr = (uintptr_t)start;
51         arg.len = (uintptr_t)end - (uintptr_t)start;
52 
53         sysarch(ARM_SYNC_ICACHE, &arg);
54     #elif defined(__ANDROID__)
55          const register int start_reg __asm("r0") = (int) (intptr_t) start;
56          const register int end_reg __asm("r1") = (int) (intptr_t) end;
57          const register int flags __asm("r2") = 0;
58          const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
59         __asm __volatile("svc 0x0" : "=r"(start_reg)
60             : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0");
61          if (start_reg != 0) {
62              compilerrt_abort();
63          }
64     #else
65         compilerrt_abort();
66     #endif
67 #elif defined(__ANDROID__) && defined(__mips__)
68   const uintptr_t start_int = (uintptr_t) start;
69   const uintptr_t end_int = (uintptr_t) end;
70   _flush_cache(start, (end_int - start_int), BCACHE);
71 #elif defined(__aarch64__) && !defined(__APPLE__)
72   uint64_t xstart = (uint64_t)(uintptr_t) start;
73   uint64_t xend = (uint64_t)(uintptr_t) end;
74 
75   // Get Cache Type Info
76   uint64_t ctr_el0;
77   __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
78 
79   /*
80    * dc & ic instructions must use 64bit registers so we don't use
81    * uintptr_t in case this runs in an IPL32 environment.
82    */
83   const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
84   for (uint64_t addr = xstart; addr < xend; addr += dcache_line_size)
85     __asm __volatile("dc cvau, %0" :: "r"(addr));
86   __asm __volatile("dsb ish");
87 
88   const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
89   for (uint64_t addr = xstart; addr < xend; addr += icache_line_size)
90     __asm __volatile("ic ivau, %0" :: "r"(addr));
91   __asm __volatile("isb sy");
92 #else
93     #if __APPLE__
94         /* On Darwin, sys_icache_invalidate() provides this functionality */
95         sys_icache_invalidate(start, end-start);
96     #else
97         compilerrt_abort();
98     #endif
99 #endif
100 }
101 
102