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