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