1*06c3fb27SDimitry Andric //===-- mem_map_base.h ------------------------------------------*- C++ -*-===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric 9*06c3fb27SDimitry Andric #ifndef SCUDO_MEM_MAP_BASE_H_ 10*06c3fb27SDimitry Andric #define SCUDO_MEM_MAP_BASE_H_ 11*06c3fb27SDimitry Andric 12*06c3fb27SDimitry Andric #include "common.h" 13*06c3fb27SDimitry Andric 14*06c3fb27SDimitry Andric namespace scudo { 15*06c3fb27SDimitry Andric 16*06c3fb27SDimitry Andric // In Scudo, every memory operation will be fulfilled through a 17*06c3fb27SDimitry Andric // platform-specific `MemMap` instance. The essential APIs are listed in the 18*06c3fb27SDimitry Andric // `MemMapBase` below. This is implemented in CRTP, so for each implementation, 19*06c3fb27SDimitry Andric // it has to implement all of the 'Impl' named functions. 20*06c3fb27SDimitry Andric template <class Derived> class MemMapBase { 21*06c3fb27SDimitry Andric public: 22*06c3fb27SDimitry Andric constexpr MemMapBase() = default; 23*06c3fb27SDimitry Andric 24*06c3fb27SDimitry Andric // This is used to map a new set of contiguous pages. Note that the `Addr` is 25*06c3fb27SDimitry Andric // only a suggestion to the system. 26*06c3fb27SDimitry Andric bool map(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 27*06c3fb27SDimitry Andric DCHECK(!isAllocated()); 28*06c3fb27SDimitry Andric return invokeImpl(&Derived::mapImpl, Addr, Size, Name, Flags); 29*06c3fb27SDimitry Andric } 30*06c3fb27SDimitry Andric 31*06c3fb27SDimitry Andric // This is used to unmap partial/full pages from the beginning or the end. 32*06c3fb27SDimitry Andric // I.e., the result pages are expected to be still contiguous. unmap(uptr Addr,uptr Size)33*06c3fb27SDimitry Andric void unmap(uptr Addr, uptr Size) { 34*06c3fb27SDimitry Andric DCHECK(isAllocated()); 35*06c3fb27SDimitry Andric DCHECK((Addr == getBase()) || (Addr + Size == getBase() + getCapacity())); 36*06c3fb27SDimitry Andric invokeImpl(&Derived::unmapImpl, Addr, Size); 37*06c3fb27SDimitry Andric } 38*06c3fb27SDimitry Andric 39*06c3fb27SDimitry Andric // This is used to remap a mapped range (either from map() or dispatched from 40*06c3fb27SDimitry Andric // ReservedMemory). For example, we have reserved several pages and then we 41*06c3fb27SDimitry Andric // want to remap them with different accessibility. 42*06c3fb27SDimitry Andric bool remap(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 43*06c3fb27SDimitry Andric DCHECK(isAllocated()); 44*06c3fb27SDimitry Andric DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 45*06c3fb27SDimitry Andric return invokeImpl(&Derived::remapImpl, Addr, Size, Name, Flags); 46*06c3fb27SDimitry Andric } 47*06c3fb27SDimitry Andric 48*06c3fb27SDimitry Andric // This is used to update the pages' access permission. For example, mark 49*06c3fb27SDimitry Andric // pages as no read/write permission. setMemoryPermission(uptr Addr,uptr Size,uptr Flags)50*06c3fb27SDimitry Andric void setMemoryPermission(uptr Addr, uptr Size, uptr Flags) { 51*06c3fb27SDimitry Andric DCHECK(isAllocated()); 52*06c3fb27SDimitry Andric DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 53*06c3fb27SDimitry Andric return invokeImpl(&Derived::setMemoryPermissionImpl, Addr, Size, Flags); 54*06c3fb27SDimitry Andric } 55*06c3fb27SDimitry Andric 56*06c3fb27SDimitry Andric // Suggest releasing a set of contiguous physical pages back to the OS. Note 57*06c3fb27SDimitry Andric // that only physical pages are supposed to be released. Any release of 58*06c3fb27SDimitry Andric // virtual pages may lead to undefined behavior. releasePagesToOS(uptr From,uptr Size)59*06c3fb27SDimitry Andric void releasePagesToOS(uptr From, uptr Size) { 60*06c3fb27SDimitry Andric DCHECK(isAllocated()); 61*06c3fb27SDimitry Andric DCHECK((From >= getBase()) && (From + Size <= getBase() + getCapacity())); 62*06c3fb27SDimitry Andric invokeImpl(&Derived::releasePagesToOSImpl, From, Size); 63*06c3fb27SDimitry Andric } 64*06c3fb27SDimitry Andric // This is similar to the above one except that any subsequent access to the 65*06c3fb27SDimitry Andric // released pages will return with zero-filled pages. releaseAndZeroPagesToOS(uptr From,uptr Size)66*06c3fb27SDimitry Andric void releaseAndZeroPagesToOS(uptr From, uptr Size) { 67*06c3fb27SDimitry Andric DCHECK(isAllocated()); 68*06c3fb27SDimitry Andric DCHECK((From >= getBase()) && (From + Size <= getBase() + getCapacity())); 69*06c3fb27SDimitry Andric invokeImpl(&Derived::releaseAndZeroPagesToOSImpl, From, Size); 70*06c3fb27SDimitry Andric } 71*06c3fb27SDimitry Andric getBase()72*06c3fb27SDimitry Andric uptr getBase() { return invokeImpl(&Derived::getBaseImpl); } getCapacity()73*06c3fb27SDimitry Andric uptr getCapacity() { return invokeImpl(&Derived::getCapacityImpl); } 74*06c3fb27SDimitry Andric isAllocated()75*06c3fb27SDimitry Andric bool isAllocated() { return getBase() != 0U; } 76*06c3fb27SDimitry Andric 77*06c3fb27SDimitry Andric protected: 78*06c3fb27SDimitry Andric template <typename R, typename... Args> invokeImpl(R (Derived::* MemFn)(Args...),Args...args)79*06c3fb27SDimitry Andric R invokeImpl(R (Derived::*MemFn)(Args...), Args... args) { 80*06c3fb27SDimitry Andric return (static_cast<Derived *>(this)->*MemFn)(args...); 81*06c3fb27SDimitry Andric } 82*06c3fb27SDimitry Andric }; 83*06c3fb27SDimitry Andric 84*06c3fb27SDimitry Andric // `ReservedMemory` is a special memory handle which can be viewed as a page 85*06c3fb27SDimitry Andric // allocator. `ReservedMemory` will reserve a contiguous pages and the later 86*06c3fb27SDimitry Andric // page request can be fulfilled at the designated address. This is used when 87*06c3fb27SDimitry Andric // we want to ensure the virtual address of the MemMap will be in a known range. 88*06c3fb27SDimitry Andric // This is implemented in CRTP, so for each 89*06c3fb27SDimitry Andric // implementation, it has to implement all of the 'Impl' named functions. 90*06c3fb27SDimitry Andric template <class Derived, typename MemMapTy> class ReservedMemory { 91*06c3fb27SDimitry Andric public: 92*06c3fb27SDimitry Andric using MemMapT = MemMapTy; 93*06c3fb27SDimitry Andric constexpr ReservedMemory() = default; 94*06c3fb27SDimitry Andric 95*06c3fb27SDimitry Andric // Reserve a chunk of memory at a suggested address. 96*06c3fb27SDimitry Andric bool create(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 97*06c3fb27SDimitry Andric DCHECK(!isCreated()); 98*06c3fb27SDimitry Andric return invokeImpl(&Derived::createImpl, Addr, Size, Name, Flags); 99*06c3fb27SDimitry Andric } 100*06c3fb27SDimitry Andric 101*06c3fb27SDimitry Andric // Release the entire reserved memory. release()102*06c3fb27SDimitry Andric void release() { 103*06c3fb27SDimitry Andric DCHECK(isCreated()); 104*06c3fb27SDimitry Andric invokeImpl(&Derived::releaseImpl); 105*06c3fb27SDimitry Andric } 106*06c3fb27SDimitry Andric 107*06c3fb27SDimitry Andric // Dispatch a sub-range of reserved memory. Note that any fragmentation of 108*06c3fb27SDimitry Andric // the reserved pages is managed by each implementation. dispatch(uptr Addr,uptr Size)109*06c3fb27SDimitry Andric MemMapT dispatch(uptr Addr, uptr Size) { 110*06c3fb27SDimitry Andric DCHECK(isCreated()); 111*06c3fb27SDimitry Andric DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 112*06c3fb27SDimitry Andric return invokeImpl(&Derived::dispatchImpl, Addr, Size); 113*06c3fb27SDimitry Andric } 114*06c3fb27SDimitry Andric getBase()115*06c3fb27SDimitry Andric uptr getBase() { return invokeImpl(&Derived::getBaseImpl); } getCapacity()116*06c3fb27SDimitry Andric uptr getCapacity() { return invokeImpl(&Derived::getCapacityImpl); } 117*06c3fb27SDimitry Andric isCreated()118*06c3fb27SDimitry Andric bool isCreated() { return getBase() != 0U; } 119*06c3fb27SDimitry Andric 120*06c3fb27SDimitry Andric protected: 121*06c3fb27SDimitry Andric template <typename R, typename... Args> invokeImpl(R (Derived::* MemFn)(Args...),Args...args)122*06c3fb27SDimitry Andric R invokeImpl(R (Derived::*MemFn)(Args...), Args... args) { 123*06c3fb27SDimitry Andric return (static_cast<Derived *>(this)->*MemFn)(args...); 124*06c3fb27SDimitry Andric } 125*06c3fb27SDimitry Andric }; 126*06c3fb27SDimitry Andric 127*06c3fb27SDimitry Andric } // namespace scudo 128*06c3fb27SDimitry Andric 129*06c3fb27SDimitry Andric #endif // SCUDO_MEM_MAP_BASE_H_ 130