1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
7
8 #include <stdint.h>
9
10 #include <cstddef>
11
12 #include "base/allocator/partition_allocator/page_allocator_constants.h"
13 #include "base/base_export.h"
14 #include "base/compiler_specific.h"
15 #include "build/build_config.h"
16
17 namespace base {
18
19 enum PageAccessibilityConfiguration {
20 PageInaccessible,
21 PageRead,
22 PageReadWrite,
23 PageReadExecute,
24 // This flag is deprecated and will go away soon.
25 // TODO(bbudge) Remove this as soon as V8 doesn't need RWX pages.
26 PageReadWriteExecute,
27 };
28
29 // macOS supports tagged memory regions, to help in debugging. On Android,
30 // these tags are used to name anonymous mappings.
31 enum class PageTag {
32 kFirst = 240, // Minimum tag value.
33 kBlinkGC = 252, // Blink GC pages.
34 kPartitionAlloc = 253, // PartitionAlloc, no matter the partition.
35 kChromium = 254, // Chromium page.
36 kV8 = 255, // V8 heap pages.
37 kLast = kV8 // Maximum tag value.
38 };
39
40 // Allocate one or more pages.
41 //
42 // The requested |address| is just a hint; the actual address returned may
43 // differ. The returned address will be aligned at least to |align| bytes.
44 // |length| is in bytes, and must be a multiple of |kPageAllocationGranularity|.
45 // |align| is in bytes, and must be a power-of-two multiple of
46 // |kPageAllocationGranularity|.
47 //
48 // If |address| is null, then a suitable and randomized address will be chosen
49 // automatically.
50 //
51 // |page_accessibility| controls the permission of the allocated pages.
52 // |page_tag| is used on some platforms to identify the source of the
53 // allocation. Use PageTag::kChromium as a catch-all category.
54 //
55 // This call will return null if the allocation cannot be satisfied.
56 BASE_EXPORT void* AllocPages(void* address,
57 size_t length,
58 size_t align,
59 PageAccessibilityConfiguration page_accessibility,
60 PageTag tag,
61 bool commit = true);
62
63 // Free one or more pages starting at |address| and continuing for |length|
64 // bytes.
65 //
66 // |address| and |length| must match a previous call to |AllocPages|. Therefore,
67 // |address| must be aligned to |kPageAllocationGranularity| bytes, and |length|
68 // must be a multiple of |kPageAllocationGranularity|.
69 BASE_EXPORT void FreePages(void* address, size_t length);
70
71 // Mark one or more system pages, starting at |address| with the given
72 // |page_accessibility|. |length| must be a multiple of |kSystemPageSize| bytes.
73 //
74 // Returns true if the permission change succeeded. In most cases you must
75 // |CHECK| the result.
76 BASE_EXPORT WARN_UNUSED_RESULT bool TrySetSystemPagesAccess(
77 void* address,
78 size_t length,
79 PageAccessibilityConfiguration page_accessibility);
80
81 // Mark one or more system pages, starting at |address| with the given
82 // |page_accessibility|. |length| must be a multiple of |kSystemPageSize| bytes.
83 //
84 // Performs a CHECK that the operation succeeds.
85 BASE_EXPORT void SetSystemPagesAccess(
86 void* address,
87 size_t length,
88 PageAccessibilityConfiguration page_accessibility);
89
90 // Decommit one or more system pages starting at |address| and continuing for
91 // |length| bytes. |length| must be a multiple of |kSystemPageSize|.
92 //
93 // Decommitted means that physical resources (RAM or swap) backing the allocated
94 // virtual address range are released back to the system, but the address space
95 // is still allocated to the process (possibly using up page table entries or
96 // other accounting resources). Any access to a decommitted region of memory
97 // is an error and will generate a fault.
98 //
99 // This operation is not atomic on all platforms.
100 //
101 // Note: "Committed memory" is a Windows Memory Subsystem concept that ensures
102 // processes will not fault when touching a committed memory region. There is
103 // no analogue in the POSIX memory API where virtual memory pages are
104 // best-effort allocated resources on the first touch. To create a
105 // platform-agnostic abstraction, this API simulates the Windows "decommit"
106 // state by both discarding the region (allowing the OS to avoid swap
107 // operations) and changing the page protections so accesses fault.
108 //
109 // TODO(ajwong): This currently does not change page protections on POSIX
110 // systems due to a perf regression. Tracked at http://crbug.com/766882.
111 BASE_EXPORT void DecommitSystemPages(void* address, size_t length);
112
113 // Recommit one or more system pages, starting at |address| and continuing for
114 // |length| bytes with the given |page_accessibility|. |length| must be a
115 // multiple of |kSystemPageSize|.
116 //
117 // Decommitted system pages must be recommitted with their original permissions
118 // before they are used again.
119 //
120 // Returns true if the recommit change succeeded. In most cases you must |CHECK|
121 // the result.
122 BASE_EXPORT WARN_UNUSED_RESULT bool RecommitSystemPages(
123 void* address,
124 size_t length,
125 PageAccessibilityConfiguration page_accessibility);
126
127 // Discard one or more system pages starting at |address| and continuing for
128 // |length| bytes. |length| must be a multiple of |kSystemPageSize|.
129 //
130 // Discarding is a hint to the system that the page is no longer required. The
131 // hint may:
132 // - Do nothing.
133 // - Discard the page immediately, freeing up physical pages.
134 // - Discard the page at some time in the future in response to memory
135 // pressure.
136 //
137 // Only committed pages should be discarded. Discarding a page does not decommit
138 // it, and it is valid to discard an already-discarded page. A read or write to
139 // a discarded page will not fault.
140 //
141 // Reading from a discarded page may return the original page content, or a page
142 // full of zeroes.
143 //
144 // Writing to a discarded page is the only guaranteed way to tell the system
145 // that the page is required again. Once written to, the content of the page is
146 // guaranteed stable once more. After being written to, the page content may be
147 // based on the original page content, or a page of zeroes.
148 BASE_EXPORT void DiscardSystemPages(void* address, size_t length);
149
150 // Rounds up |address| to the next multiple of |kSystemPageSize|. Returns
151 // 0 for an |address| of 0.
RoundUpToSystemPage(uintptr_t address)152 constexpr ALWAYS_INLINE uintptr_t RoundUpToSystemPage(uintptr_t address) {
153 return (address + kSystemPageOffsetMask) & kSystemPageBaseMask;
154 }
155
156 // Rounds down |address| to the previous multiple of |kSystemPageSize|. Returns
157 // 0 for an |address| of 0.
RoundDownToSystemPage(uintptr_t address)158 constexpr ALWAYS_INLINE uintptr_t RoundDownToSystemPage(uintptr_t address) {
159 return address & kSystemPageBaseMask;
160 }
161
162 // Rounds up |address| to the next multiple of |kPageAllocationGranularity|.
163 // Returns 0 for an |address| of 0.
164 constexpr ALWAYS_INLINE uintptr_t
RoundUpToPageAllocationGranularity(uintptr_t address)165 RoundUpToPageAllocationGranularity(uintptr_t address) {
166 return (address + kPageAllocationGranularityOffsetMask) &
167 kPageAllocationGranularityBaseMask;
168 }
169
170 // Rounds down |address| to the previous multiple of
171 // |kPageAllocationGranularity|. Returns 0 for an |address| of 0.
172 constexpr ALWAYS_INLINE uintptr_t
RoundDownToPageAllocationGranularity(uintptr_t address)173 RoundDownToPageAllocationGranularity(uintptr_t address) {
174 return address & kPageAllocationGranularityBaseMask;
175 }
176
177 // Reserves (at least) |size| bytes of address space, aligned to
178 // |kPageAllocationGranularity|. This can be called early on to make it more
179 // likely that large allocations will succeed. Returns true if the reservation
180 // succeeded, false if the reservation failed or a reservation was already made.
181 BASE_EXPORT bool ReserveAddressSpace(size_t size);
182
183 // Releases any reserved address space. |AllocPages| calls this automatically on
184 // an allocation failure. External allocators may also call this on failure.
185 //
186 // Returns true when an existing reservation was released.
187 BASE_EXPORT bool ReleaseReservation();
188
189 // Returns true if there is currently an address space reservation.
190 BASE_EXPORT bool HasReservationForTesting();
191
192 // Returns |errno| (POSIX) or the result of |GetLastError| (Windows) when |mmap|
193 // (POSIX) or |VirtualAlloc| (Windows) fails.
194 BASE_EXPORT uint32_t GetAllocPageErrorCode();
195
196 } // namespace base
197
198 #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
199