summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorMarkus Wick <degasus@users.noreply.github.com>2016-09-10 08:08:14 +0200
committerGitHub <noreply@github.com>2016-09-10 08:08:14 +0200
commit077fa099ea2dff45af80904c37f01ac9db9851a4 (patch)
tree25224ec1bc8689098699ae68415c5f806dda9cc4 /Source
parent6e488e65e3782537e81b91696bc36dfc2edbc9f9 (diff)
parent976da3707a5578162b602dea7a681da5edd21579 (diff)
Merge pull request #4204 from lewurm/arm64-icache-big-little-fix
arm64: fixes around icache flushing
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Common/Arm64Emitter.cpp33
1 files changed, 28 insertions, 5 deletions
diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp
index 380437e3b0..d49c799744 100644
--- a/Source/Core/Common/Arm64Emitter.cpp
+++ b/Source/Core/Common/Arm64Emitter.cpp
@@ -329,11 +329,34 @@ void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end)
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
#else
-#ifdef __clang__
- __clear_cache(start, end);
-#else
- __builtin___clear_cache(start, end);
-#endif
+ // Don't rely on GCC's __clear_cache implementation, as it caches
+ // icache/dcache cache line sizes, that can vary between cores on
+ // big.LITTLE architectures.
+ u64 addr, ctr_el0;
+ static size_t icache_line_size = 0xffff, dcache_line_size = 0xffff;
+ size_t isize, dsize;
+
+ __asm__ volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
+ isize = 4 << ((ctr_el0 >> 0) & 0xf);
+ dsize = 4 << ((ctr_el0 >> 16) & 0xf);
+
+ // use the global minimum cache line size
+ icache_line_size = isize = icache_line_size < isize ? icache_line_size : isize;
+ dcache_line_size = dsize = dcache_line_size < dsize ? dcache_line_size : dsize;
+
+ addr = (u64)start & ~(u64)(dsize - 1);
+ for (; addr < (u64)end; addr += dsize)
+ // use "civac" instead of "cvau", as this is the suggested workaround for
+ // Cortex-A53 errata 819472, 826319, 827319 and 824069.
+ __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
+ __asm__ volatile("dsb ish" : : : "memory");
+
+ addr = (u64)start & ~(u64)(isize - 1);
+ for (; addr < (u64)end; addr += isize)
+ __asm__ volatile("ic ivau, %0" : : "r"(addr) : "memory");
+
+ __asm__ volatile("dsb ish" : : : "memory");
+ __asm__ volatile("isb" : : : "memory");
#endif
}