xref: /freebsd/contrib/llvm-project/llvm/lib/Support/Unix/Memory.inc (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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