Skip to content

Commit a939257

Browse files
committedNov 28, 2017
[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
1 parent 542485f commit a939257

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed
 

‎llvm/lib/Support/Unix/Memory.inc

+24-4
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,12 @@ Memory::allocateMappedMemory(size_t NumBytes,
126126
Result.Address = Addr;
127127
Result.Size = NumPages*PageSize;
128128

129-
if (PFlags & MF_EXEC)
130-
Memory::InvalidateInstructionCache(Result.Address, Result.Size);
129+
// Rely on protectMappedMemory to invalidate instruction cache.
130+
if (PFlags & MF_EXEC) {
131+
EC = Memory::protectMappedMemory (Result, PFlags);
132+
if (EC != std::error_code())
133+
return MemoryBlock();
134+
}
131135

132136
return Result;
133137
}
@@ -156,15 +160,31 @@ Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) {
156160
return std::error_code(EINVAL, std::generic_category());
157161

158162
int Protect = getPosixProtectionFlags(Flags);
159-
160163
uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize);
161164
uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize);
165+
166+
bool InvalidateCache = (Flags & MF_EXEC);
167+
168+
#if defined(__arm__) || defined(__aarch64__)
169+
// Certain ARM implementations treat icache clear instruction as a memory read,
170+
// and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need
171+
// to temporarily add PROT_READ for the sake of flushing the instruction caches.
172+
if (InvalidateCache && !(Protect & PROT_READ)) {
173+
int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ);
174+
if (Result != 0)
175+
return std::error_code(errno, std::generic_category());
176+
177+
Memory::InvalidateInstructionCache(M.Address, M.Size);
178+
InvalidateCache = false;
179+
}
180+
#endif
181+
162182
int Result = ::mprotect((void *)Start, End - Start, Protect);
163183

164184
if (Result != 0)
165185
return std::error_code(errno, std::generic_category());
166186

167-
if (Flags & MF_EXEC)
187+
if (InvalidateCache)
168188
Memory::InvalidateInstructionCache(M.Address, M.Size);
169189

170190
return std::error_code();

0 commit comments

Comments
 (0)
Please sign in to comment.