diff options
Diffstat (limited to 'lib/builtins/clear_cache.c')
| -rw-r--r-- | lib/builtins/clear_cache.c | 66 | 
1 files changed, 63 insertions, 3 deletions
diff --git a/lib/builtins/clear_cache.c b/lib/builtins/clear_cache.c index 86e68afad3b7..61b1e9bbb5c0 100644 --- a/lib/builtins/clear_cache.c +++ b/lib/builtins/clear_cache.c @@ -13,12 +13,62 @@  #if __APPLE__    #include <libkern/OSCacheControl.h>  #endif +#if defined(__FreeBSD__) && defined(__arm__) +  #include <sys/types.h> +  #include <machine/sysarch.h> +#endif +  #if defined(__NetBSD__) && defined(__arm__)    #include <machine/sysarch.h>  #endif  #if defined(__ANDROID__) && defined(__mips__)    #include <sys/cachectl.h> +  #include <sys/syscall.h> +  #ifdef __LP64__ +    /* +     * clear_mips_cache - Invalidates instruction cache for Mips. +     */ +    static void clear_mips_cache(const void* Addr, size_t Size) { +      asm volatile ( +        ".set push\n" +        ".set noreorder\n" +        ".set noat\n" +        "beq %[Size], $zero, 20f\n"          /* If size == 0, branch around. */ +        "nop\n" +        "daddu %[Size], %[Addr], %[Size]\n"  /* Calculate end address + 1 */ +        "rdhwr $v0, $1\n"                    /* Get step size for SYNCI. +                                                $1 is $HW_SYNCI_Step */ +        "beq $v0, $zero, 20f\n"              /* If no caches require +                                                synchronization, branch +                                                around. */ +        "nop\n" +        "10:\n" +        "synci 0(%[Addr])\n"                 /* Synchronize all caches around +                                                address. */ +        "daddu %[Addr], %[Addr], $v0\n"      /* Add step size. */ +        "sltu $at, %[Addr], %[Size]\n"       /* Compare current with end +                                                address. */ +        "bne $at, $zero, 10b\n"              /* Branch if more to do. */ +        "nop\n" +        "sync\n"                             /* Clear memory hazards. */ +        "20:\n" +        "bal 30f\n" +        "nop\n" +        "30:\n" +        "daddiu $ra, $ra, 12\n"              /* $ra has a value of $pc here. +                                                Add offset of 12 to point to the +                                                instruction after the last nop. +                                              */ +        "jr.hb $ra\n"                        /* Return, clearing instruction +                                                hazards. */ +        "nop\n" +        ".set pop\n" +        : [Addr] "+r"(Addr), [Size] "+r"(Size) +        :: "at", "ra", "v0", "memory" +      ); +    } +  #endif  #endif  #if defined(__ANDROID__) && defined(__arm__) @@ -39,7 +89,7 @@ void __clear_cache(void *start, void *end) {   * so there is nothing to do   */  #elif defined(__arm__) && !defined(__APPLE__) -    #if defined(__NetBSD__) +    #if defined(__FreeBSD__) || defined(__NetBSD__)          struct arm_sync_icache_args arg;          arg.addr = (uintptr_t)start; @@ -47,7 +97,7 @@ void __clear_cache(void *start, void *end) {          sysarch(ARM_SYNC_ICACHE, &arg);      #elif defined(__ANDROID__) -         const register int start_reg __asm("r0") = (int) (intptr_t) start; +         register int start_reg __asm("r0") = (int) (intptr_t) start;           const register int end_reg __asm("r1") = (int) (intptr_t) end;           const register int flags __asm("r2") = 0;           const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush; @@ -62,7 +112,17 @@ void __clear_cache(void *start, void *end) {  #elif defined(__ANDROID__) && defined(__mips__)    const uintptr_t start_int = (uintptr_t) start;    const uintptr_t end_int = (uintptr_t) end; -  _flush_cache(start, (end_int - start_int), BCACHE); +    #ifdef __LP64__ +        // Call synci implementation for short address range. +        const uintptr_t address_range_limit = 256; +        if ((end_int - start_int) <= address_range_limit) { +            clear_mips_cache(start, (end_int - start_int)); +        } else { +            syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE); +        } +    #else +        syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE); +    #endif  #elif defined(__aarch64__) && !defined(__APPLE__)    uint64_t xstart = (uint64_t)(uintptr_t) start;    uint64_t xend = (uint64_t)(uintptr_t) end;  | 
