From: Peter Smith Date: Tue, 28 Nov 2017 12:34:05 +0000 (+0000) Subject: [ARM][AArch64] Workaround ARM/AArch64 peculiarity in clearing icache. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e3d7c90a7c221b7e96df27751110131cdfa6449;p=llvm [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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319166 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index 31480162c87..848548d1817 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -126,8 +126,12 @@ Memory::allocateMappedMemory(size_t NumBytes, 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 MemoryBlock &M, unsigned Flags) { 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();