[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
This commit is contained in:
Peter Smith 2017-11-28 12:34:05 +00:00
parent 542485f29c
commit a939257a42
1 changed files with 24 additions and 4 deletions

View File

@ -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();