Merge pull request #3549 from lewurm/arm64-icache-big-little-fix
authormonojenkins <jo.shields+jenkins@xamarin.com>
Mon, 12 Sep 2016 17:30:08 +0000 (18:30 +0100)
committerGitHub <noreply@github.com>
Mon, 12 Sep 2016 17:30:08 +0000 (18:30 +0100)
commit4e441ecc2a8b9e66459e1df19ea5804e1fea668e
tree9496e1e3a218e97d919998acd695a3cc6d7ddc60
parent104fd9c63861e391e502942643863385417c251a
parent44520cdd9c7eee06cb0b248c5da8177299674ba1
Merge pull request #3549 from lewurm/arm64-icache-big-little-fix

[arm64] fixes around icache flushing

This fixes https://bugzilla.xamarin.com/show_bug.cgi?id=39859

The problem in `emit_thunk` and the workarounds for the Cortex A53 errata are unrelated to the bug above, but they don't hurt either.

The basic problem that we see is that the Exynos 8890 SoC (shipped for example in the world edition of the Samsung Galaxy S7) is a big.LITTLE architecture with two different CPUs, four of each. `__clear_cache` of GCC [1], the built-in that we use to flush the instruction cache, correctly reads the cache line sizes for data- and instruction cache from the CPU and then caches that result. However, the two CPUs on the Exynos 8890 have two different cache line sizes for the instruction cache (128 bytes vs. 64 bytes): If we happen to initialize the cache line sizes with the larger one, we only flush every other cache line if the code runs on the second CPU model.

Neither V8 [2] and LLVM [3] do caching of the cache line sizes, but just read it every time from the register.  We have a slightly different solution, where we cache _and_ read the value every time and try to determine a global minimum across CPUs, in case we get scheduled to a different CPU by the kernel during the flushing loop.

[1] https://android.googlesource.com/toolchain/gcc/+/master/gcc-4.9/libgcc/config/aarch64/sync-cache.c#33
[2] https://github.com/v8/v8/commit/fec99c689b8587b863df4a5c4793c601772ef663
[3] https://github.com/llvm-mirror/compiler-rt/blob/ff75f2a0260b1940436a483413091c5770427c04/lib/builtins/clear_cache.c#L146