xref: /aosp_15_r20/external/scudo/standalone/mem_map_base.h (revision 76559068c068bd27e82aff38fac3bfc865233bca)
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