diff options
author | Peter Smith <peter.smith@linaro.org> | 2017-11-28 12:34:05 +0000 |
---|---|---|
committer | Peter Smith <peter.smith@linaro.org> | 2017-11-28 12:34:05 +0000 |
commit | a939257a42286accab8a55f0eb20c1ad117b06c7 (patch) | |
tree | a17970981b79020fef99deac6ff87de5e047d964 /llvm/lib/Support/Unix | |
parent | 542485f29ce22ac0beed33b57bf51662f7d0e877 (diff) | |
download | bcm5719-llvm-a939257a42286accab8a55f0eb20c1ad117b06c7.tar.gz bcm5719-llvm-a939257a42286accab8a55f0eb20c1ad117b06c7.zip |
[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
llvm-svn: 319166
Diffstat (limited to 'llvm/lib/Support/Unix')
-rw-r--r-- | llvm/lib/Support/Unix/Memory.inc | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/llvm/lib/Support/Unix/Memory.inc b/llvm/lib/Support/Unix/Memory.inc index 31480162c87..848548d1817 100644 --- a/llvm/lib/Support/Unix/Memory.inc +++ b/llvm/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(); |