1 /****************************************************************************
2 **
3 ** Copyright (C) Rolland Dudemaine All rights reserved.
4 ** Copyright (C) 2016 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtQml module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "config.h"
42 #include "OSAllocator.h"
43
44 #include <INTEGRITY.h>
45 #include <memory_region.h>
46 #include <set>
47 #include <wtf/Assertions.h>
48 #include <wtf/UnusedParam.h>
49
50 #define ASP_PAGESIZE 0x1000
51
52 namespace WTF {
53 struct MRPair {
54 mutable MemoryRegion pmr;
55 mutable MemoryRegion vmr;
56
57 mutable bool mapped;
58
59 Address start;
60
MRPairWTF::MRPair61 MRPair(Address _start = 0) :
62 pmr(0),
63 vmr(0),
64 mapped(false),
65 start(_start)
66 {}
67
operator <WTF::MRPair68 bool operator<(const MRPair& rhs) const
69 {
70 return this->start < rhs.start;
71 }
72 };
73
74 class MRContainer
75 {
76 private:
77 std::set<MRPair> mrset;
78 LocalMutex iteratorGuard;
79 public:
MRContainer()80 MRContainer() {
81 CheckSuccess(CreateLocalMutex(&iteratorGuard));
82 }
getMRPair(Address start)83 const MRPair* getMRPair(Address start) {
84 WaitForLocalMutex(iteratorGuard);
85 auto pairIterator = mrset.find(MRPair(start));
86 const MRPair* result = ((pairIterator == mrset.end()) ? NULL : &(*pairIterator));
87 ReleaseLocalMutex(iteratorGuard);
88 return result;
89 }
deleteMRPair(const MRPair * pair)90 Error deleteMRPair(const MRPair* pair) {
91 int erased = 0;
92 WaitForLocalMutex(iteratorGuard);
93 erased = mrset.erase(*pair);
94 ReleaseLocalMutex(iteratorGuard);
95 if(erased == 1)
96 return Success;
97 else
98 return ArgumentError; /* An exception could be thrown in this case */
99 }
insertMRPair(MRPair * pair)100 Error insertMRPair(MRPair* pair) {
101 WaitForLocalMutex(iteratorGuard);
102 auto inserted = mrset.insert(*pair);
103 ReleaseLocalMutex(iteratorGuard);
104 if(inserted.second == true)
105 return Success;
106 else
107 return Failure; /* An exception could be thrown in this case */
108 }
~MRContainer()109 ~MRContainer() {
110 CheckSuccess(CloseLocalMutex(iteratorGuard));
111 }
112 };
113
114 static MRContainer memoryRegionsContainer;
115
setAttributes(MemoryRegion mr,bool writable,bool executable)116 Error setAttributes(MemoryRegion mr, bool writable, bool executable)
117 {
118 Value attributes = MEMORY_READ;
119 if(writable)
120 attributes |= MEMORY_WRITE;
121 if(executable)
122 attributes |= MEMORY_EXEC;
123 return SetMemoryRegionAttributes(mr, attributes);
124 }
125
setMemoryAttributes(void * addr,size_t size,bool writable,bool executable)126 void OSAllocator::setMemoryAttributes(void* addr, size_t size, bool writable, bool executable)
127 {
128 Address addressIterator = Address(addr);
129 for(int i=0; i<(size + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
130 const MRPair* pair = memoryRegionsContainer.getMRPair(addressIterator);
131 CheckSuccess(setAttributes(pair->vmr, writable, executable));
132 addressIterator += ASP_PAGESIZE;
133 }
134 }
135
reserveUncommitted(size_t bytes,Usage usage,bool writable,bool executable)136 void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
137 {
138 MemoryRegion VMR;
139
140 Address virtualStart, length;
141
142 CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
143 CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
144 Address addressIterator = virtualStart;
145 for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
146 MRPair pair;
147 pair.start = addressIterator;
148 CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
149 CheckSuccess(setAttributes(pair.vmr, writable, executable));
150
151 memoryRegionsContainer.insertMRPair(&pair);
152 addressIterator += ASP_PAGESIZE;
153 }
154
155 CheckSuccess(CloseMemoryRegion(VMR));
156 return (void*)virtualStart;
157 }
158
reserveAndCommit(size_t bytes,Usage usage,bool writable,bool executable,bool includesGuardPages)159 void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
160 {
161 MemoryRegion VMR;
162
163 Address virtualStart, length;
164
165 CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
166 CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
167
168 Address addressIterator = virtualStart;
169 for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
170 MRPair pair;
171 pair.start = addressIterator;
172 CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
173 CheckSuccess(setAttributes(pair.vmr, writable, executable));
174 /* Do not map the first and the last pages if guard pages are required */
175 if(!includesGuardPages || (i!=0 && i!= (bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE -1))
176 {
177 CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair.pmr));
178 CheckSuccess(MapMemoryRegion(pair.vmr, pair.pmr));
179 pair.mapped = true;
180 }
181
182 memoryRegionsContainer.insertMRPair(&pair);
183 addressIterator += ASP_PAGESIZE;
184 }
185
186 CheckSuccess(CloseMemoryRegion(VMR));
187 return (void*)virtualStart;
188 }
189
commit(void * address,size_t bytes,bool writable,bool executable)190 void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
191 {
192 for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
193 {
194 const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
195 if(pair == NULL)
196 return;
197 CheckSuccess(setAttributes(pair->vmr, writable, executable));
198 CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair->pmr));
199 CheckSuccess(MapMemoryRegion(pair->vmr, pair->pmr));
200 pair->mapped = true;
201 address = (char*)address + ASP_PAGESIZE;
202 }
203 }
204
decommit(void * address,size_t bytes)205 void OSAllocator::decommit(void* address, size_t bytes)
206 {
207 for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
208 {
209 const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
210 if(pair == NULL)
211 return;
212 if(pair->mapped == false)
213 continue;
214
215 CheckSuccess(UnmapMemoryRegion(pair->vmr));
216 CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
217 pair->mapped = false;
218 address = (char*)address + ASP_PAGESIZE;
219 }
220 }
221
releaseDecommitted(void * address,size_t bytes)222 void OSAllocator::releaseDecommitted(void* address, size_t bytes)
223 {
224 for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
225 {
226 const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
227 if(pair == NULL)
228 return;
229 /* Check if the memory is still committed */
230 if(pair->mapped == true)
231 {
232 CheckSuccess(UnmapMemoryRegion(pair->vmr));
233 CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
234 pair->mapped = false;
235 }
236 CheckSuccess(AddToMemoryPool(__ghs_VirtualMemoryRegionPool, pair->vmr));
237 address = (char*)address + ASP_PAGESIZE;
238
239 memoryRegionsContainer.deleteMRPair(pair);
240 }
241 }
242
canAllocateExecutableMemory()243 bool OSAllocator::canAllocateExecutableMemory()
244 {
245 return true;
246 }
247
248 } // namespace WTF
249