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