1 // Copyright 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "aemu/base/SubAllocator.h"
15
16 #include "aemu/base/address_space.h"
17 #include "aemu/base/files/Stream.h"
18
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22
23 namespace android {
24 namespace base {
25
26 class SubAllocator::Impl {
27 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)28 Impl(
29 void* _buffer,
30 uint64_t _totalSize,
31 uint64_t _pageSize) :
32 buffer(_buffer),
33 totalSize(_totalSize),
34 pageSize(_pageSize),
35 startAddr((uintptr_t)buffer),
36 endAddr(startAddr + totalSize) {
37
38 address_space_allocator_init(
39 &addr_alloc,
40 totalSize,
41 32);
42 }
43
~Impl()44 ~Impl() {
45 address_space_allocator_destroy_nocleanup(&addr_alloc);
46 }
47
clear()48 void clear() {
49 address_space_allocator_destroy_nocleanup(&addr_alloc);
50 address_space_allocator_init(
51 &addr_alloc,
52 totalSize,
53 32);
54 }
55
save(Stream * stream)56 bool save(Stream* stream) {
57 address_space_allocator_iter_func_t allocatorSaver =
58 [](void* context, struct address_space_allocator* allocator) {
59 Stream* stream = reinterpret_cast<Stream*>(context);
60 stream->putBe32(allocator->size);
61 stream->putBe32(allocator->capacity);
62 stream->putBe64(allocator->total_bytes);
63 };
64 address_block_iter_func_t allocatorBlockSaver =
65 [](void* context, struct address_block* block) {
66 Stream* stream = reinterpret_cast<Stream*>(context);
67 stream->putBe64(block->offset);
68 stream->putBe64(block->size_available);
69 };
70 address_space_allocator_run(
71 &addr_alloc,
72 (void*)stream,
73 allocatorSaver,
74 allocatorBlockSaver);
75
76 stream->putBe64(pageSize);
77 stream->putBe64(totalSize);
78 stream->putBe32(allocCount);
79
80 return true;
81 }
82
load(Stream * stream)83 bool load(Stream* stream) {
84 clear();
85 address_space_allocator_iter_func_t allocatorLoader =
86 [](void* context, struct address_space_allocator* allocator) {
87 Stream* stream = reinterpret_cast<Stream*>(context);
88 allocator->size = stream->getBe32();
89 allocator->capacity = stream->getBe32();
90 allocator->total_bytes = stream->getBe64();
91 };
92 address_block_iter_func_t allocatorBlockLoader =
93 [](void* context, struct address_block* block) {
94 Stream* stream = reinterpret_cast<Stream*>(context);
95 block->offset = stream->getBe64();
96 block->size_available = stream->getBe64();
97 };
98 address_space_allocator_run(
99 &addr_alloc,
100 (void*)stream,
101 allocatorLoader,
102 allocatorBlockLoader);
103
104 pageSize = stream->getBe64();
105 totalSize = stream->getBe64();
106 allocCount = stream->getBe32();
107
108 return true;
109 }
110
postLoad(void * postLoadBuffer)111 bool postLoad(void* postLoadBuffer) {
112 buffer = postLoadBuffer;
113 startAddr =
114 (uint64_t)(uintptr_t)postLoadBuffer;
115 return true;
116 }
117
rangeCheck(const char * task,void * ptr)118 void rangeCheck(const char* task, void* ptr) {
119 uint64_t addr = (uintptr_t)ptr;
120 if (addr < startAddr ||
121 addr > endAddr) {
122 std::stringstream ss;
123 ss << "SubAllocator " << task << ": ";
124 ss << "Out of range: " << std::hex << addr << " ";
125 ss << "Range: " <<
126 std::hex << startAddr << " " <<
127 std::hex << endAddr;
128 std::string msg = ss.str();
129 fprintf(stderr, "%s: range check failed: [%s]\n", __func__, msg.c_str());
130 }
131 }
132
getOffset(void * checkedPtr)133 uint64_t getOffset(void* checkedPtr) {
134 uint64_t addr = (uintptr_t)checkedPtr;
135 return addr - startAddr;
136 }
137
free(void * ptr)138 bool free(void* ptr) {
139 if (!ptr) return false;
140
141 rangeCheck("free", ptr);
142 if (EINVAL == address_space_allocator_deallocate(
143 &addr_alloc, getOffset(ptr))) {
144 return false;
145 }
146
147 --allocCount;
148 return true;
149 }
150
freeAll()151 void freeAll() {
152 address_space_allocator_reset(&addr_alloc);
153 allocCount = 0;
154 }
155
alloc(size_t wantedSize)156 void* alloc(size_t wantedSize) {
157 if (wantedSize == 0) return nullptr;
158
159 size_t toPageSize =
160 pageSize *
161 ((wantedSize + pageSize - 1) / pageSize);
162
163 uint64_t offset =
164 address_space_allocator_allocate(
165 &addr_alloc, toPageSize);
166
167 if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
168 return nullptr;
169 }
170
171 ++allocCount;
172 return (void*)(uintptr_t)(startAddr + offset);
173 }
174
allocFixed(size_t wantedSize,uint64_t offset)175 void* allocFixed(size_t wantedSize, uint64_t offset) {
176
177 if (wantedSize == 0) return nullptr;
178
179 size_t toPageSize =
180 pageSize *
181 ((wantedSize + pageSize - 1) / pageSize);
182
183 if (address_space_allocator_allocate_fixed(
184 &addr_alloc, toPageSize, offset)) {
185 return nullptr;
186 }
187
188 ++allocCount;
189 return (void*)(uintptr_t)(startAddr + offset);
190 }
191
empty() const192 bool empty() const {
193 return allocCount == 0;
194 }
195
196 void* buffer;
197 uint64_t totalSize;
198 uint64_t pageSize;
199 uint64_t startAddr;
200 uint64_t endAddr;
201 struct address_space_allocator addr_alloc;
202 uint32_t allocCount = 0;
203 };
204
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)205 SubAllocator::SubAllocator(
206 void* buffer,
207 uint64_t totalSize,
208 uint64_t pageSize) :
209 mImpl(
210 new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
211
~SubAllocator()212 SubAllocator::~SubAllocator() {
213 delete mImpl;
214 }
215
216 // Snapshotting
save(Stream * stream)217 bool SubAllocator::save(Stream* stream) {
218 return mImpl->save(stream);
219 }
220
load(Stream * stream)221 bool SubAllocator::load(Stream* stream) {
222 return mImpl->load(stream);
223 }
224
postLoad(void * postLoadBuffer)225 bool SubAllocator::postLoad(void* postLoadBuffer) {
226 return mImpl->postLoad(postLoadBuffer);
227 }
228
alloc(size_t wantedSize)229 void* SubAllocator::alloc(size_t wantedSize) {
230 return mImpl->alloc(wantedSize);
231 }
232
allocFixed(size_t wantedSize,uint64_t offset)233 void* SubAllocator::allocFixed(size_t wantedSize, uint64_t offset) {
234 return mImpl->allocFixed(wantedSize, offset);
235 }
236
free(void * ptr)237 bool SubAllocator::free(void* ptr) {
238 return mImpl->free(ptr);
239 }
240
freeAll()241 void SubAllocator::freeAll() {
242 mImpl->freeAll();
243 }
244
getOffset(void * ptr)245 uint64_t SubAllocator::getOffset(void* ptr) {
246 return mImpl->getOffset(ptr);
247 }
248
empty() const249 bool SubAllocator::empty() const {
250 return mImpl->empty();
251 }
252
253 } // namespace base
254 } // namespace android
255