1218885Sdim//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// 2218885Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6218885Sdim// 7218885Sdim//===----------------------------------------------------------------------===// 8218885Sdim// 9218885Sdim// This file provides the Win32 specific implementation of various Memory 10218885Sdim// management utilities 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim#include "llvm/Support/DataTypes.h" 15243830Sdim#include "llvm/Support/ErrorHandling.h" 16218885Sdim#include "llvm/Support/Process.h" 17276479Sdim#include "llvm/Support/WindowsError.h" 18249423Sdim 19249423Sdim// The Windows.h header must be the last one included. 20360784Sdim#include "llvm/Support/Windows/WindowsSupport.h" 21218885Sdim 22360784Sdimstatic DWORD getWindowsProtectionFlags(unsigned Flags) { 23353358Sdim switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { 24243830Sdim // Contrary to what you might expect, the Windows page protection flags 25243830Sdim // are not a bitwise combination of RWX values 26243830Sdim case llvm::sys::Memory::MF_READ: 27243830Sdim return PAGE_READONLY; 28243830Sdim case llvm::sys::Memory::MF_WRITE: 29243830Sdim // Note: PAGE_WRITE is not supported by VirtualProtect 30243830Sdim return PAGE_READWRITE; 31243830Sdim case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: 32243830Sdim return PAGE_READWRITE; 33243830Sdim case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: 34243830Sdim return PAGE_EXECUTE_READ; 35243830Sdim case llvm::sys::Memory::MF_READ | 36243830Sdim llvm::sys::Memory::MF_WRITE | 37243830Sdim llvm::sys::Memory::MF_EXEC: 38243830Sdim return PAGE_EXECUTE_READWRITE; 39243830Sdim case llvm::sys::Memory::MF_EXEC: 40243830Sdim return PAGE_EXECUTE; 41243830Sdim default: 42243830Sdim llvm_unreachable("Illegal memory protection flag specified!"); 43243830Sdim } 44243830Sdim // Provide a default return value as required by some compilers. 45243830Sdim return PAGE_NOACCESS; 46243830Sdim} 47243830Sdim 48353358Sdim// While we'd be happy to allocate single pages, the Windows allocation 49353358Sdim// granularity may be larger than a single page (in practice, it is 64K) 50353358Sdim// so mapping less than that will create an unreachable fragment of memory. 51360784Sdimstatic size_t getAllocationGranularity() { 52243830Sdim SYSTEM_INFO Info; 53243830Sdim ::GetSystemInfo(&Info); 54243830Sdim if (Info.dwPageSize > Info.dwAllocationGranularity) 55243830Sdim return Info.dwPageSize; 56243830Sdim else 57243830Sdim return Info.dwAllocationGranularity; 58243830Sdim} 59243830Sdim 60353358Sdim// Large/huge memory pages need explicit process permissions in order to be 61353358Sdim// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 62353358Sdim// Also large pages need to be manually enabled on your OS. If all this is 63353358Sdim// sucessfull, we return the minimal large memory page size. 64353358Sdimstatic size_t enableProcessLargePages() { 65353358Sdim HANDLE Token = 0; 66353358Sdim size_t LargePageMin = GetLargePageMinimum(); 67353358Sdim if (LargePageMin) 68353358Sdim OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 69353358Sdim &Token); 70353358Sdim if (!Token) 71353358Sdim return 0; 72353358Sdim LUID Luid; 73353358Sdim if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { 74353358Sdim CloseHandle(Token); 75353358Sdim return 0; 76353358Sdim } 77353358Sdim TOKEN_PRIVILEGES TP{}; 78353358Sdim TP.PrivilegeCount = 1; 79353358Sdim TP.Privileges[0].Luid = Luid; 80353358Sdim TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 81353358Sdim if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { 82353358Sdim CloseHandle(Token); 83353358Sdim return 0; 84353358Sdim } 85353358Sdim DWORD E = GetLastError(); 86353358Sdim CloseHandle(Token); 87353358Sdim if (E == ERROR_SUCCESS) 88353358Sdim return LargePageMin; 89353358Sdim return 0; 90353358Sdim} 91353358Sdim 92218885Sdimnamespace llvm { 93243830Sdimnamespace sys { 94218885Sdim 95218885Sdim//===----------------------------------------------------------------------===// 96218885Sdim//=== WARNING: Implementation here must contain only Win32 specific code 97218885Sdim//=== and must not be UNIX code 98218885Sdim//===----------------------------------------------------------------------===// 99218885Sdim 100243830SdimMemoryBlock Memory::allocateMappedMemory(size_t NumBytes, 101243830Sdim const MemoryBlock *const NearBlock, 102243830Sdim unsigned Flags, 103276479Sdim std::error_code &EC) { 104276479Sdim EC = std::error_code(); 105243830Sdim if (NumBytes == 0) 106243830Sdim return MemoryBlock(); 107218885Sdim 108353358Sdim static size_t DefaultGranularity = getAllocationGranularity(); 109353358Sdim static size_t LargePageGranularity = enableProcessLargePages(); 110353358Sdim 111353358Sdim DWORD AllocType = MEM_RESERVE | MEM_COMMIT; 112353358Sdim bool HugePages = false; 113353358Sdim size_t Granularity = DefaultGranularity; 114353358Sdim 115353358Sdim if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { 116353358Sdim AllocType |= MEM_LARGE_PAGES; 117353358Sdim HugePages = true; 118353358Sdim Granularity = LargePageGranularity; 119288943Sdim } 120288943Sdim 121353358Sdim size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; 122218885Sdim 123243830Sdim uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + 124353358Sdim NearBlock->allocatedSize() 125261991Sdim : 0; 126218885Sdim 127243830Sdim // If the requested address is not aligned to the allocation granularity, 128243830Sdim // round up to get beyond NearBlock. VirtualAlloc would have rounded down. 129243830Sdim if (Start && Start % Granularity != 0) 130243830Sdim Start += Granularity - Start % Granularity; 131243830Sdim 132243830Sdim DWORD Protect = getWindowsProtectionFlags(Flags); 133243830Sdim 134353358Sdim size_t AllocSize = NumBlocks * Granularity; 135353358Sdim void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), 136353358Sdim AllocSize, AllocType, Protect); 137243830Sdim if (PA == NULL) { 138353358Sdim if (NearBlock || HugePages) { 139353358Sdim // Try again without the NearBlock hint and without large memory pages 140353358Sdim return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); 141226633Sdim } 142276479Sdim EC = mapWindowsError(::GetLastError()); 143218885Sdim return MemoryBlock(); 144218885Sdim } 145218885Sdim 146243830Sdim MemoryBlock Result; 147243830Sdim Result.Address = PA; 148353358Sdim Result.AllocatedSize = AllocSize; 149353358Sdim Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); 150261991Sdim 151243830Sdim if (Flags & MF_EXEC) 152353358Sdim Memory::InvalidateInstructionCache(Result.Address, AllocSize); 153243830Sdim 154243830Sdim return Result; 155218885Sdim} 156218885Sdim 157276479Sdim std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { 158353358Sdim if (M.Address == 0 || M.AllocatedSize == 0) 159276479Sdim return std::error_code(); 160243830Sdim 161218885Sdim if (!VirtualFree(M.Address, 0, MEM_RELEASE)) 162276479Sdim return mapWindowsError(::GetLastError()); 163243830Sdim 164243830Sdim M.Address = 0; 165353358Sdim M.AllocatedSize = 0; 166243830Sdim 167276479Sdim return std::error_code(); 168218885Sdim} 169218885Sdim 170276479Sdim std::error_code Memory::protectMappedMemory(const MemoryBlock &M, 171243830Sdim unsigned Flags) { 172353358Sdim if (M.Address == 0 || M.AllocatedSize == 0) 173276479Sdim return std::error_code(); 174243830Sdim 175243830Sdim DWORD Protect = getWindowsProtectionFlags(Flags); 176243830Sdim 177243830Sdim DWORD OldFlags; 178353358Sdim if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) 179276479Sdim return mapWindowsError(::GetLastError()); 180243830Sdim 181243830Sdim if (Flags & MF_EXEC) 182353358Sdim Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); 183243830Sdim 184276479Sdim return std::error_code(); 185243830Sdim} 186243830Sdim 187243830Sdim/// InvalidateInstructionCache - Before the JIT can run a block of code 188243830Sdim/// that has been emitted it must invalidate the instruction cache on some 189243830Sdim/// platforms. 190243830Sdimvoid Memory::InvalidateInstructionCache( 191243830Sdim const void *Addr, size_t Len) { 192243830Sdim FlushInstructionCache(GetCurrentProcess(), Addr, Len); 193243830Sdim} 194243830Sdim 195243830Sdim} // namespace sys 196243830Sdim} // namespace llvm 197