10b57cec5SDimitry Andric//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// 20b57cec5SDimitry Andric// 30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric// 70b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric// 90b57cec5SDimitry Andric// This file defines some functions for various memory management utilities. 100b57cec5SDimitry Andric// 110b57cec5SDimitry Andric//===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric#include "Unix.h" 140b57cec5SDimitry Andric#include "llvm/Config/config.h" 155ffd83dbSDimitry Andric#include "llvm/Support/Alignment.h" 160b57cec5SDimitry Andric#include "llvm/Support/DataTypes.h" 170b57cec5SDimitry Andric#include "llvm/Support/ErrorHandling.h" 180b57cec5SDimitry Andric#include "llvm/Support/Process.h" 1981ad6265SDimitry Andric#include "llvm/Support/Valgrind.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric#ifdef HAVE_SYS_MMAN_H 220b57cec5SDimitry Andric#include <sys/mman.h> 230b57cec5SDimitry Andric#endif 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric#ifdef __APPLE__ 260b57cec5SDimitry Andric#include <mach/mach.h> 270b57cec5SDimitry Andric#endif 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric#ifdef __Fuchsia__ 300b57cec5SDimitry Andric#include <zircon/syscalls.h> 310b57cec5SDimitry Andric#endif 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric#if defined(__APPLE__) 340b57cec5SDimitry Andricextern "C" void sys_icache_invalidate(const void *Addr, size_t len); 350b57cec5SDimitry Andric#else 360b57cec5SDimitry Andricextern "C" void __clear_cache(void *, void *); 370b57cec5SDimitry Andric#endif 380b57cec5SDimitry Andric 39480093f4SDimitry Andricstatic int getPosixProtectionFlags(unsigned Flags) { 400b57cec5SDimitry Andric switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { 410b57cec5SDimitry Andric case llvm::sys::Memory::MF_READ: 420b57cec5SDimitry Andric return PROT_READ; 430b57cec5SDimitry Andric case llvm::sys::Memory::MF_WRITE: 440b57cec5SDimitry Andric return PROT_WRITE; 450b57cec5SDimitry Andric case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE: 460b57cec5SDimitry Andric return PROT_READ | PROT_WRITE; 470b57cec5SDimitry Andric case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC: 480b57cec5SDimitry Andric return PROT_READ | PROT_EXEC; 490b57cec5SDimitry Andric case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | 500b57cec5SDimitry Andric llvm::sys::Memory::MF_EXEC: 510b57cec5SDimitry Andric return PROT_READ | PROT_WRITE | PROT_EXEC; 520b57cec5SDimitry Andric case llvm::sys::Memory::MF_EXEC: 53bdd1243dSDimitry Andric#if defined(__FreeBSD__) || defined(__powerpc__) 540b57cec5SDimitry Andric // On PowerPC, having an executable page that has no read permission 550b57cec5SDimitry Andric // can have unintended consequences. The function InvalidateInstruction- 560b57cec5SDimitry Andric // Cache uses instructions dcbf and icbi, both of which are treated by 570b57cec5SDimitry Andric // the processor as loads. If the page has no read permissions, 580b57cec5SDimitry Andric // executing these instructions will result in a segmentation fault. 590b57cec5SDimitry Andric return PROT_READ | PROT_EXEC; 600b57cec5SDimitry Andric#else 610b57cec5SDimitry Andric return PROT_EXEC; 620b57cec5SDimitry Andric#endif 630b57cec5SDimitry Andric default: 640b57cec5SDimitry Andric llvm_unreachable("Illegal memory protection flag specified!"); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric // Provide a default return value as required by some compilers. 670b57cec5SDimitry Andric return PROT_NONE; 680b57cec5SDimitry Andric} 690b57cec5SDimitry Andric 700b57cec5SDimitry Andricnamespace llvm { 710b57cec5SDimitry Andricnamespace sys { 720b57cec5SDimitry Andric 73bdd1243dSDimitry AndricMemoryBlock Memory::allocateMappedMemory(size_t NumBytes, 740b57cec5SDimitry Andric const MemoryBlock *const NearBlock, 75bdd1243dSDimitry Andric unsigned PFlags, std::error_code &EC) { 760b57cec5SDimitry Andric EC = std::error_code(); 770b57cec5SDimitry Andric if (NumBytes == 0) 780b57cec5SDimitry Andric return MemoryBlock(); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric // On platforms that have it, we can use MAP_ANON to get a memory-mapped 810b57cec5SDimitry Andric // page without file backing, but we need a fallback of opening /dev/zero 820b57cec5SDimitry Andric // for strictly POSIX platforms instead. 830b57cec5SDimitry Andric int fd; 840b57cec5SDimitry Andric#if defined(MAP_ANON) 850b57cec5SDimitry Andric fd = -1; 860b57cec5SDimitry Andric#else 870b57cec5SDimitry Andric fd = open("/dev/zero", O_RDWR); 880b57cec5SDimitry Andric if (fd == -1) { 89*0fca6ea1SDimitry Andric EC = errnoAsErrorCode(); 900b57cec5SDimitry Andric return MemoryBlock(); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric#endif 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric int MMFlags = MAP_PRIVATE; 950b57cec5SDimitry Andric#if defined(MAP_ANON) 960b57cec5SDimitry Andric MMFlags |= MAP_ANON; 970b57cec5SDimitry Andric#endif 980b57cec5SDimitry Andric int Protect = getPosixProtectionFlags(PFlags); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric#if defined(__NetBSD__) && defined(PROT_MPROTECT) 1010b57cec5SDimitry Andric Protect |= PROT_MPROTECT(PROT_READ | PROT_WRITE | PROT_EXEC); 1020b57cec5SDimitry Andric#endif 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // Use any near hint and the page size to set a page-aligned starting address 1050b57cec5SDimitry Andric uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 106bdd1243dSDimitry Andric NearBlock->allocatedSize() 107bdd1243dSDimitry Andric : 0; 1080b57cec5SDimitry Andric static const size_t PageSize = Process::getPageSizeEstimate(); 1090b57cec5SDimitry Andric const size_t NumPages = (NumBytes + PageSize - 1) / PageSize; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric if (Start && Start % PageSize) 1120b57cec5SDimitry Andric Start += PageSize - Start % PageSize; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // FIXME: Handle huge page requests (MF_HUGE_HINT). 115bdd1243dSDimitry Andric void *Addr = ::mmap(reinterpret_cast<void *>(Start), PageSize * NumPages, 116bdd1243dSDimitry Andric Protect, MMFlags, fd, 0); 1170b57cec5SDimitry Andric if (Addr == MAP_FAILED) { 1180b57cec5SDimitry Andric if (NearBlock) { // Try again without a near hint 1190b57cec5SDimitry Andric#if !defined(MAP_ANON) 1200b57cec5SDimitry Andric close(fd); 1210b57cec5SDimitry Andric#endif 1220b57cec5SDimitry Andric return allocateMappedMemory(NumBytes, nullptr, PFlags, EC); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 125*0fca6ea1SDimitry Andric EC = errnoAsErrorCode(); 1260b57cec5SDimitry Andric#if !defined(MAP_ANON) 1270b57cec5SDimitry Andric close(fd); 1280b57cec5SDimitry Andric#endif 1290b57cec5SDimitry Andric return MemoryBlock(); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric#if !defined(MAP_ANON) 1330b57cec5SDimitry Andric close(fd); 1340b57cec5SDimitry Andric#endif 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric MemoryBlock Result; 1370b57cec5SDimitry Andric Result.Address = Addr; 1380b57cec5SDimitry Andric Result.AllocatedSize = PageSize * NumPages; 1390b57cec5SDimitry Andric Result.Flags = PFlags; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric // Rely on protectMappedMemory to invalidate instruction cache. 1420b57cec5SDimitry Andric if (PFlags & MF_EXEC) { 1430b57cec5SDimitry Andric EC = Memory::protectMappedMemory(Result, PFlags); 1440b57cec5SDimitry Andric if (EC != std::error_code()) 1450b57cec5SDimitry Andric return MemoryBlock(); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric return Result; 1490b57cec5SDimitry Andric} 1500b57cec5SDimitry Andric 151bdd1243dSDimitry Andricstd::error_code Memory::releaseMappedMemory(MemoryBlock &M) { 1520b57cec5SDimitry Andric if (M.Address == nullptr || M.AllocatedSize == 0) 1530b57cec5SDimitry Andric return std::error_code(); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric if (0 != ::munmap(M.Address, M.AllocatedSize)) 156*0fca6ea1SDimitry Andric return errnoAsErrorCode(); 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric M.Address = nullptr; 1590b57cec5SDimitry Andric M.AllocatedSize = 0; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric return std::error_code(); 1620b57cec5SDimitry Andric} 1630b57cec5SDimitry Andric 164bdd1243dSDimitry Andricstd::error_code Memory::protectMappedMemory(const MemoryBlock &M, 165bdd1243dSDimitry Andric unsigned Flags) { 1668bcb0991SDimitry Andric static const Align PageSize = Align(Process::getPageSizeEstimate()); 1670b57cec5SDimitry Andric if (M.Address == nullptr || M.AllocatedSize == 0) 1680b57cec5SDimitry Andric return std::error_code(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric if (!Flags) 1710b57cec5SDimitry Andric return std::error_code(EINVAL, std::generic_category()); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric int Protect = getPosixProtectionFlags(Flags); 174bdd1243dSDimitry Andric uintptr_t Start = 175bdd1243dSDimitry Andric alignAddr((const uint8_t *)M.Address - PageSize.value() + 1, PageSize); 176bdd1243dSDimitry Andric uintptr_t End = 177bdd1243dSDimitry Andric alignAddr((const uint8_t *)M.Address + M.AllocatedSize, PageSize); 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool InvalidateCache = (Flags & MF_EXEC); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric#if defined(__arm__) || defined(__aarch64__) 182bdd1243dSDimitry Andric // Certain ARM implementations treat icache clear instruction as a memory 183bdd1243dSDimitry Andric // read, and CPU segfaults on trying to clear cache on !PROT_READ page. 184bdd1243dSDimitry Andric // Therefore we need to temporarily add PROT_READ for the sake of flushing the 185bdd1243dSDimitry Andric // instruction caches. 1860b57cec5SDimitry Andric if (InvalidateCache && !(Protect & PROT_READ)) { 1870b57cec5SDimitry Andric int Result = ::mprotect((void *)Start, End - Start, Protect | PROT_READ); 1880b57cec5SDimitry Andric if (Result != 0) 189*0fca6ea1SDimitry Andric return errnoAsErrorCode(); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); 1920b57cec5SDimitry Andric InvalidateCache = false; 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric#endif 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric int Result = ::mprotect((void *)Start, End - Start, Protect); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric if (Result != 0) 199*0fca6ea1SDimitry Andric return errnoAsErrorCode(); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric if (InvalidateCache) 2020b57cec5SDimitry Andric Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric return std::error_code(); 2050b57cec5SDimitry Andric} 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric/// InvalidateInstructionCache - Before the JIT can run a block of code 2080b57cec5SDimitry Andric/// that has been emitted it must invalidate the instruction cache on some 2090b57cec5SDimitry Andric/// platforms. 210bdd1243dSDimitry Andricvoid Memory::InvalidateInstructionCache(const void *Addr, size_t Len) { 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric// icache invalidation for PPC and ARM. 2130b57cec5SDimitry Andric#if defined(__APPLE__) 2140b57cec5SDimitry Andric 215bdd1243dSDimitry Andric#if (defined(__powerpc__) || defined(__arm__) || defined(__arm64__)) 2160b57cec5SDimitry Andric sys_icache_invalidate(const_cast<void *>(Addr), Len); 2170b57cec5SDimitry Andric#endif 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric#elif defined(__Fuchsia__) 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric zx_status_t Status = zx_cache_flush(Addr, Len, ZX_CACHE_FLUSH_INSN); 2220b57cec5SDimitry Andric assert(Status == ZX_OK && "cannot invalidate instruction cache"); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric#else 2250b57cec5SDimitry Andric 226bdd1243dSDimitry Andric#if defined(__powerpc__) && defined(__GNUC__) 2270b57cec5SDimitry Andric const size_t LineSize = 32; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric const intptr_t Mask = ~(LineSize - 1); 2300b57cec5SDimitry Andric const intptr_t StartLine = ((intptr_t)Addr) & Mask; 2310b57cec5SDimitry Andric const intptr_t EndLine = ((intptr_t)Addr + Len + LineSize - 1) & Mask; 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) 2340b57cec5SDimitry Andric asm volatile("dcbf 0, %0" : : "r"(Line)); 2350b57cec5SDimitry Andric asm volatile("sync"); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) 2380b57cec5SDimitry Andric asm volatile("icbi 0, %0" : : "r"(Line)); 2390b57cec5SDimitry Andric asm volatile("isync"); 2405f757f3fSDimitry Andric#elif (defined(__arm__) || defined(__aarch64__) || defined(__loongarch__) || \ 2415f757f3fSDimitry Andric defined(__mips__)) && \ 2420b57cec5SDimitry Andric defined(__GNUC__) 2430b57cec5SDimitry Andric // FIXME: Can we safely always call this for __GNUC__ everywhere? 2440b57cec5SDimitry Andric const char *Start = static_cast<const char *>(Addr); 2450b57cec5SDimitry Andric const char *End = Start + Len; 2460b57cec5SDimitry Andric __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); 2470b57cec5SDimitry Andric#endif 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric#endif // end apple 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric ValgrindDiscardTranslations(Addr, Len); 2520b57cec5SDimitry Andric} 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric} // namespace sys 2550b57cec5SDimitry Andric} // namespace llvm 256