1//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines some functions for various memory management utilities. 11// 12//===----------------------------------------------------------------------===// 13 14#include "Unix.h" 15#include "llvm/Config/config.h" 16#include "llvm/Support/DataTypes.h" 17#include "llvm/Support/ErrorHandling.h" 18#include "llvm/Support/Process.h" 19 20#ifdef HAVE_SYS_MMAN_H 21#include <sys/mman.h> 22#endif 23 24#ifdef __APPLE__ 25#include <mach/mach.h> 26#endif 27 28#ifdef __Fuchsia__ 29#include <zircon/syscalls.h> 30#endif 31 32#if defined(__mips__) 33# if defined(__OpenBSD__) 34# include <mips64/sysarch.h> 35# elif !defined(__FreeBSD__) 36# include <sys/cachectl.h> 37# endif 38#endif 39 40#if defined(__APPLE__) 41extern "C" void sys_icache_invalidate(const void *Addr, size_t len); 42#else 43extern "C" void __clear_cache(void *, void*); 44#endif 45 46namespace { 47 48int getPosixProtectionFlags(unsigned Flags) { 49 switch (Flags) { 50 case llvm::sys::Memory::MF_READ: 51 return PROT_READ; 52 case llvm::sys::Memory::MF_WRITE: 53 return PROT_WRITE; 54 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: 55 return PROT_READ | PROT_WRITE; 56 case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: 57 return PROT_READ | PROT_EXEC; 58 case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | 59 llvm::sys::Memory::MF_EXEC: 60 return PROT_READ | PROT_WRITE | PROT_EXEC; 61 case llvm::sys::Memory::MF_EXEC: 62#if defined(__FreeBSD__) 63 // On PowerPC, having an executable page that has no read permission 64 // can have unintended consequences. The function InvalidateInstruction- 65 // Cache uses instructions dcbf and icbi, both of which are treated by 66 // the processor as loads. If the page has no read permissions, 67 // executing these instructions will result in a segmentation fault. 68 // Somehow, this problem is not present on Linux, but it does happen 69 // on FreeBSD. 70 return PROT_READ | PROT_EXEC; 71#else 72 return PROT_EXEC; 73#endif 74 default: 75 llvm_unreachable("Illegal memory protection flag specified!"); 76 } 77 // Provide a default return value as required by some compilers. 78 return PROT_NONE; 79} 80 81} // anonymous namespace 82 83namespace llvm { 84namespace sys { 85 86MemoryBlock 87Memory::allocateMappedMemory(size_t NumBytes, 88 const MemoryBlock *const NearBlock, 89 unsigned PFlags, 90 std::error_code &EC) { 91 EC = std::error_code(); 92 if (NumBytes == 0) 93 return MemoryBlock(); 94 95 static const size_t PageSize = Process::getPageSize(); 96 const size_t NumPages = (NumBytes+PageSize-1)/PageSize; 97 98 int fd = -1; 99 100 int MMFlags = MAP_PRIVATE | 101#ifdef MAP_ANONYMOUS 102 MAP_ANONYMOUS 103#else 104 MAP_ANON 105#endif 106 ; // Ends statement above 107 108 int Protect = getPosixProtectionFlags(PFlags); 109 110#if defined(__NetBSD__) && defined(PROT_MPROTECT) 111 Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC); 112#endif 113 114 // Use any near hint and the page size to set a page-aligned starting address 115 uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 116 NearBlock->size() : 0; 117 if (Start && Start % PageSize) 118 Start += PageSize - Start % PageSize; 119 120 void *Addr = ::mmap(reinterpret_cast<void*>(Start), PageSize*NumPages, 121 Protect, MMFlags, fd, 0); 122 if (Addr == MAP_FAILED) { 123 if (NearBlock) //Try again without a near hint 124 return allocateMappedMemory(NumBytes, nullptr, PFlags, EC); 125 126 EC = std::error_code(errno, std::generic_category()); 127 return MemoryBlock(); 128 } 129 130 MemoryBlock Result; 131 Result.Address = Addr; 132 Result.Size = NumPages*PageSize; 133 134 // Rely on protectMappedMemory to invalidate instruction cache. 135 if (PFlags & MF_EXEC) { 136 EC = Memory::protectMappedMemory (Result, PFlags); 137 if (EC != std::error_code()) 138 return MemoryBlock(); 139 } 140 141 return Result; 142} 143 144std::error_code 145Memory::releaseMappedMemory(MemoryBlock &M) { 146 if (M.Address == nullptr || M.Size == 0) 147 return std::error_code(); 148 149 if (0 != ::munmap(M.Address, M.Size)) 150 return std::error_code(errno, std::generic_category()); 151 152 M.Address = nullptr; 153 M.Size = 0; 154 155 return std::error_code(); 156} 157 158std::error_code 159Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { 160 static const size_t PageSize = Process::getPageSize(); 161 if (M.Address == nullptr || M.Size == 0) 162 return std::error_code(); 163 164 if (!Flags) 165 return std::error_code(EINVAL, std::generic_category()); 166 167 int Protect = getPosixProtectionFlags(Flags); 168 uintptr_t Start = alignAddr((uint8_t *)M.Address - PageSize + 1, PageSize); 169 uintptr_t End = alignAddr((uint8_t *)M.Address + M.Size, PageSize); 170 171 bool InvalidateCache = (Flags & MF_EXEC); 172 173#if defined(__arm__) || defined(__aarch64__) 174 // Certain ARM implementations treat icache clear instruction as a memory read, 175 // and CPU segfaults on trying to clear cache on !PROT_READ page. Therefore we need 176 // to temporarily add PROT_READ for the sake of flushing the instruction caches. 177 if (InvalidateCache && !(Protect & PROT_READ)) { 178 int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ); 179 if (Result != 0) 180 return std::error_code(errno, std::generic_category()); 181 182 Memory::InvalidateInstructionCache(M.Address, M.Size); 183 InvalidateCache = false; 184 } 185#endif 186 187 int Result = ::mprotect((void *)Start, End - Start, Protect); 188 189 if (Result != 0) 190 return std::error_code(errno, std::generic_category()); 191 192 if (InvalidateCache) 193 Memory::InvalidateInstructionCache(M.Address, M.Size); 194 195 return std::error_code(); 196} 197 198/// InvalidateInstructionCache - Before the JIT can run a block of code 199/// that has been emitted it must invalidate the instruction cache on some 200/// platforms. 201void Memory::InvalidateInstructionCache(const void *Addr, 202 size_t Len) { 203 204// icache invalidation for PPC and ARM. 205#if defined(__APPLE__) 206 207# if (defined(__POWERPC__) || defined (__ppc__) || \ 208 defined(_POWER) || defined(_ARCH_PPC) || defined(__arm__) || \ 209 defined(__arm64__)) 210 sys_icache_invalidate(const_cast<void *>(Addr), Len); 211# endif 212 213#elif defined(__Fuchsia__) 214 215 zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN); 216 assert(Status == ZX_OK && "cannot invalidate instruction cache"); 217 218#else 219 220# if (defined(__POWERPC__) || defined (__ppc__) || \ 221 defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) 222 const size_t LineSize = 32; 223 224 const intptr_t Mask = ~(LineSize - 1); 225 const intptr_t StartLine = ((intptr_t) Addr) & Mask; 226 const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; 227 228 for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) 229 asm volatile("dcbf 0, %0" : : "r"(Line)); 230 asm volatile("sync"); 231 232 for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) 233 asm volatile("icbi 0, %0" : : "r"(Line)); 234 asm volatile("isync"); 235# elif (defined(__arm__) || defined(__aarch64__) || defined(__mips__)) && \ 236 defined(__GNUC__) 237 // FIXME: Can we safely always call this for __GNUC__ everywhere? 238 const char *Start = static_cast<const char *>(Addr); 239 const char *End = Start + Len; 240 __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); 241# endif 242 243#endif // end apple 244 245 ValgrindDiscardTranslations(Addr, Len); 246} 247 248} // namespace sys 249} // namespace llvm 250