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