1405ceaa0SChia-hung Duan //===-- mem_map_base.h ------------------------------------------*- C++ -*-===// 2405ceaa0SChia-hung Duan // 3405ceaa0SChia-hung Duan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4405ceaa0SChia-hung Duan // See https://llvm.org/LICENSE.txt for license information. 5405ceaa0SChia-hung Duan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6405ceaa0SChia-hung Duan // 7405ceaa0SChia-hung Duan //===----------------------------------------------------------------------===// 8405ceaa0SChia-hung Duan 9405ceaa0SChia-hung Duan #ifndef SCUDO_MEM_MAP_BASE_H_ 10405ceaa0SChia-hung Duan #define SCUDO_MEM_MAP_BASE_H_ 11405ceaa0SChia-hung Duan 12405ceaa0SChia-hung Duan #include "common.h" 13405ceaa0SChia-hung Duan 14405ceaa0SChia-hung Duan namespace scudo { 15405ceaa0SChia-hung Duan 16405ceaa0SChia-hung Duan // In Scudo, every memory operation will be fulfilled through a 17405ceaa0SChia-hung Duan // platform-specific `MemMap` instance. The essential APIs are listed in the 18405ceaa0SChia-hung Duan // `MemMapBase` below. This is implemented in CRTP, so for each implementation, 19405ceaa0SChia-hung Duan // it has to implement all of the 'Impl' named functions. 20405ceaa0SChia-hung Duan template <class Derived> class MemMapBase { 21405ceaa0SChia-hung Duan public: 22405ceaa0SChia-hung Duan constexpr MemMapBase() = default; 23405ceaa0SChia-hung Duan 24405ceaa0SChia-hung Duan // This is used to map a new set of contiguous pages. Note that the `Addr` is 25405ceaa0SChia-hung Duan // only a suggestion to the system. 26405ceaa0SChia-hung Duan bool map(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 27405ceaa0SChia-hung Duan DCHECK(!isAllocated()); 28405ceaa0SChia-hung Duan return invokeImpl(&Derived::mapImpl, Addr, Size, Name, Flags); 29405ceaa0SChia-hung Duan } 30405ceaa0SChia-hung Duan 31405ceaa0SChia-hung Duan // This is used to unmap partial/full pages from the beginning or the end. 32405ceaa0SChia-hung Duan // I.e., the result pages are expected to be still contiguous. 33405ceaa0SChia-hung Duan void unmap(uptr Addr, uptr Size) { 34405ceaa0SChia-hung Duan DCHECK(isAllocated()); 35405ceaa0SChia-hung Duan DCHECK((Addr == getBase()) || (Addr + Size == getBase() + getCapacity())); 36405ceaa0SChia-hung Duan invokeImpl(&Derived::unmapImpl, Addr, Size); 37405ceaa0SChia-hung Duan } 38*dd741fc1SChiaHungDuan // A default implementation to unmap all pages. 39*dd741fc1SChiaHungDuan void unmap() { unmap(getBase(), getCapacity()); } 40405ceaa0SChia-hung Duan 41405ceaa0SChia-hung Duan // This is used to remap a mapped range (either from map() or dispatched from 42405ceaa0SChia-hung Duan // ReservedMemory). For example, we have reserved several pages and then we 43405ceaa0SChia-hung Duan // want to remap them with different accessibility. 44405ceaa0SChia-hung Duan bool remap(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 45405ceaa0SChia-hung Duan DCHECK(isAllocated()); 46bd96d7b8SFabio D'Urso DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 47405ceaa0SChia-hung Duan return invokeImpl(&Derived::remapImpl, Addr, Size, Name, Flags); 48405ceaa0SChia-hung Duan } 49405ceaa0SChia-hung Duan 5009239636SChia-hung Duan // This is used to update the pages' access permission. For example, mark 5109239636SChia-hung Duan // pages as no read/write permission. 5209239636SChia-hung Duan void setMemoryPermission(uptr Addr, uptr Size, uptr Flags) { 5309239636SChia-hung Duan DCHECK(isAllocated()); 54bd96d7b8SFabio D'Urso DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 55280ffafcSChia-hung Duan return invokeImpl(&Derived::setMemoryPermissionImpl, Addr, Size, Flags); 5609239636SChia-hung Duan } 5709239636SChia-hung Duan 58405ceaa0SChia-hung Duan // Suggest releasing a set of contiguous physical pages back to the OS. Note 59405ceaa0SChia-hung Duan // that only physical pages are supposed to be released. Any release of 60405ceaa0SChia-hung Duan // virtual pages may lead to undefined behavior. 61405ceaa0SChia-hung Duan void releasePagesToOS(uptr From, uptr Size) { 62405ceaa0SChia-hung Duan DCHECK(isAllocated()); 63bd96d7b8SFabio D'Urso DCHECK((From >= getBase()) && (From + Size <= getBase() + getCapacity())); 64405ceaa0SChia-hung Duan invokeImpl(&Derived::releasePagesToOSImpl, From, Size); 65405ceaa0SChia-hung Duan } 66405ceaa0SChia-hung Duan // This is similar to the above one except that any subsequent access to the 67405ceaa0SChia-hung Duan // released pages will return with zero-filled pages. 68405ceaa0SChia-hung Duan void releaseAndZeroPagesToOS(uptr From, uptr Size) { 69405ceaa0SChia-hung Duan DCHECK(isAllocated()); 70bd96d7b8SFabio D'Urso DCHECK((From >= getBase()) && (From + Size <= getBase() + getCapacity())); 71405ceaa0SChia-hung Duan invokeImpl(&Derived::releaseAndZeroPagesToOSImpl, From, Size); 72405ceaa0SChia-hung Duan } 73405ceaa0SChia-hung Duan 74405ceaa0SChia-hung Duan uptr getBase() { return invokeImpl(&Derived::getBaseImpl); } 75405ceaa0SChia-hung Duan uptr getCapacity() { return invokeImpl(&Derived::getCapacityImpl); } 76405ceaa0SChia-hung Duan 77405ceaa0SChia-hung Duan bool isAllocated() { return getBase() != 0U; } 78405ceaa0SChia-hung Duan 79405ceaa0SChia-hung Duan protected: 80405ceaa0SChia-hung Duan template <typename R, typename... Args> 81405ceaa0SChia-hung Duan R invokeImpl(R (Derived::*MemFn)(Args...), Args... args) { 82405ceaa0SChia-hung Duan return (static_cast<Derived *>(this)->*MemFn)(args...); 83405ceaa0SChia-hung Duan } 84405ceaa0SChia-hung Duan }; 85405ceaa0SChia-hung Duan 86405ceaa0SChia-hung Duan // `ReservedMemory` is a special memory handle which can be viewed as a page 87405ceaa0SChia-hung Duan // allocator. `ReservedMemory` will reserve a contiguous pages and the later 88405ceaa0SChia-hung Duan // page request can be fulfilled at the designated address. This is used when 89405ceaa0SChia-hung Duan // we want to ensure the virtual address of the MemMap will be in a known range. 90405ceaa0SChia-hung Duan // This is implemented in CRTP, so for each 91405ceaa0SChia-hung Duan // implementation, it has to implement all of the 'Impl' named functions. 92405ceaa0SChia-hung Duan template <class Derived, typename MemMapTy> class ReservedMemory { 93405ceaa0SChia-hung Duan public: 94405ceaa0SChia-hung Duan using MemMapT = MemMapTy; 95405ceaa0SChia-hung Duan constexpr ReservedMemory() = default; 96405ceaa0SChia-hung Duan 97405ceaa0SChia-hung Duan // Reserve a chunk of memory at a suggested address. 98405ceaa0SChia-hung Duan bool create(uptr Addr, uptr Size, const char *Name, uptr Flags = 0) { 99405ceaa0SChia-hung Duan DCHECK(!isCreated()); 100405ceaa0SChia-hung Duan return invokeImpl(&Derived::createImpl, Addr, Size, Name, Flags); 101405ceaa0SChia-hung Duan } 102405ceaa0SChia-hung Duan 103405ceaa0SChia-hung Duan // Release the entire reserved memory. 104405ceaa0SChia-hung Duan void release() { 105405ceaa0SChia-hung Duan DCHECK(isCreated()); 106405ceaa0SChia-hung Duan invokeImpl(&Derived::releaseImpl); 107405ceaa0SChia-hung Duan } 108405ceaa0SChia-hung Duan 109405ceaa0SChia-hung Duan // Dispatch a sub-range of reserved memory. Note that any fragmentation of 110405ceaa0SChia-hung Duan // the reserved pages is managed by each implementation. 111405ceaa0SChia-hung Duan MemMapT dispatch(uptr Addr, uptr Size) { 112405ceaa0SChia-hung Duan DCHECK(isCreated()); 113bd96d7b8SFabio D'Urso DCHECK((Addr >= getBase()) && (Addr + Size <= getBase() + getCapacity())); 114405ceaa0SChia-hung Duan return invokeImpl(&Derived::dispatchImpl, Addr, Size); 115405ceaa0SChia-hung Duan } 116405ceaa0SChia-hung Duan 117405ceaa0SChia-hung Duan uptr getBase() { return invokeImpl(&Derived::getBaseImpl); } 118405ceaa0SChia-hung Duan uptr getCapacity() { return invokeImpl(&Derived::getCapacityImpl); } 119405ceaa0SChia-hung Duan 120405ceaa0SChia-hung Duan bool isCreated() { return getBase() != 0U; } 121405ceaa0SChia-hung Duan 122405ceaa0SChia-hung Duan protected: 123405ceaa0SChia-hung Duan template <typename R, typename... Args> 124405ceaa0SChia-hung Duan R invokeImpl(R (Derived::*MemFn)(Args...), Args... args) { 125405ceaa0SChia-hung Duan return (static_cast<Derived *>(this)->*MemFn)(args...); 126405ceaa0SChia-hung Duan } 127405ceaa0SChia-hung Duan }; 128405ceaa0SChia-hung Duan 129405ceaa0SChia-hung Duan } // namespace scudo 130405ceaa0SChia-hung Duan 131405ceaa0SChia-hung Duan #endif // SCUDO_MEM_MAP_BASE_H_ 132