[llvm] r319166 - [ARM][AArch64] Workaround ARM/AArch64 peculiarity in clearing icache.
Peter Smith via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 28 04:34:05 PST 2017
Author: psmith
Date: Tue Nov 28 04:34:05 2017
New Revision: 319166
URL: http://llvm.org/viewvc/llvm-project?rev=319166&view=rev
Log:
[ARM][AArch64] Workaround ARM/AArch64 peculiarity in clearing icache.
Certain ARM implementations treat icache clear instruction as a memory read,
and CPU segfaults on trying to clear cache on !PROT_READ page.
We workaround this in Memory::protectMappedMemory by adding
PROT_READ to affected pages, clearing the cache, and then setting
desired protection.
This fixes "AllocationTests/MappedMemoryTest.***/3" unit-tests on
affected hardware.
Reviewers: psmith, zatrazz, kristof.beyls, lhames
Reviewed By: lhames
Subscribers: llvm-commits, krytarowski, peter.smith, jgreenhalgh, aemerson,
rengolin
Patch by maxim-kuvrykov!
Differential Revision: https://reviews.llvm.org/D40423
Modified:
llvm/trunk/lib/Support/Unix/Memory.inc
Modified: llvm/trunk/lib/Support/Unix/Memory.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Memory.inc?rev=319166&r1=319165&r2=319166&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Unix/Memory.inc (original)
+++ llvm/trunk/lib/Support/Unix/Memory.inc Tue Nov 28 04:34:05 2017
@@ -126,8 +126,12 @@ Memory::allocateMappedMemory(size_t NumB
Result.Address = Addr;
Result.Size = NumPages*PageSize;
- if (PFlags & MF_EXEC)
- Memory::InvalidateInstructionCache(Result.Address, Result.Size);
+ // Rely on protectMappedMemory to invalidate instruction cache.
+ if (PFlags & MF_EXEC) {
+ EC = Memory::protectMappedMemory (Result, PFlags);
+ if (EC != std::error_code())
+ return MemoryBlock();
+ }
return Result;
}
@@ -156,15 +160,31 @@ Memory::protectMappedMemory(const Memory
return std::error_code(EINVAL, std::generic_category());
int Protect = getPosixProtectionFlags(Flags);
-
uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize);
uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize);
+
+ bool InvalidateCache = (Flags & MF_EXEC);
+
+#if defined(__arm__) || defined(__aarch64__)
+ // Certain ARM implementations treat icache clear instruction as a memory read,
+ // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need
+ // to temporarily add PROT_READ for the sake of flushing the instruction caches.
+ if (InvalidateCache && !(Protect & PROT_READ)) {
+ int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ);
+ if (Result != 0)
+ return std::error_code(errno, std::generic_category());
+
+ Memory::InvalidateInstructionCache(M.Address, M.Size);
+ InvalidateCache = false;
+ }
+#endif
+
int Result = ::mprotect((void *)Start, End - Start, Protect);
if (Result != 0)
return std::error_code(errno, std::generic_category());
- if (Flags & MF_EXEC)
+ if (InvalidateCache)
Memory::InvalidateInstructionCache(M.Address, M.Size);
return std::error_code();
More information about the llvm-commits
mailing list