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 "android/base/AndroidSubAllocator.h"
15 
16 #include "android/base/address_space.h"
17 #include "android/base/files/Stream.h"
18 
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22 
23 #include <log/log.h>
24 
25 namespace android {
26 namespace base {
27 namespace guest {
28 
29 class SubAllocator::Impl {
30 public:
Impl(void * _buffer,uint64_t _totalSize,uint64_t _pageSize)31     Impl(
32         void* _buffer,
33         uint64_t _totalSize,
34         uint64_t _pageSize) :
35         buffer(_buffer),
36         totalSize(_totalSize),
37         pageSize(_pageSize),
38         startAddr((uintptr_t)buffer),
39         endAddr(startAddr + totalSize) {
40 
41         address_space_allocator_init(
42             &addr_alloc,
43             totalSize,
44             32);
45     }
46 
~Impl()47     ~Impl() {
48         address_space_allocator_destroy_nocleanup(&addr_alloc);
49     }
50 
clear()51     void clear() {
52         address_space_allocator_destroy_nocleanup(&addr_alloc);
53         address_space_allocator_init(
54             &addr_alloc,
55             totalSize,
56             32);
57     }
58 
save(Stream * stream)59     bool save(Stream* stream) {
60         address_space_allocator_iter_func_t allocatorSaver =
61             [](void* context, struct address_space_allocator* allocator) {
62                 Stream* stream = reinterpret_cast<Stream*>(context);
63                 stream->putBe32(allocator->size);
64                 stream->putBe32(allocator->capacity);
65                 stream->putBe64(allocator->total_bytes);
66             };
67         address_block_iter_func_t allocatorBlockSaver =
68             [](void* context, struct address_block* block) {
69                 Stream* stream = reinterpret_cast<Stream*>(context);
70                 stream->putBe64(block->offset);
71                 stream->putBe64(block->size_available);
72             };
73         address_space_allocator_run(
74             &addr_alloc,
75             (void*)stream,
76             allocatorSaver,
77             allocatorBlockSaver);
78 
79         stream->putBe64(pageSize);
80         stream->putBe64(totalSize);
81         stream->putBe32(allocCount);
82 
83         return true;
84     }
85 
load(Stream * stream)86     bool load(Stream* stream) {
87         clear();
88         address_space_allocator_iter_func_t allocatorLoader =
89             [](void* context, struct address_space_allocator* allocator) {
90                 Stream* stream = reinterpret_cast<Stream*>(context);
91                 allocator->size = stream->getBe32();
92                 allocator->capacity = stream->getBe32();
93                 allocator->total_bytes = stream->getBe64();
94             };
95         address_block_iter_func_t allocatorBlockLoader =
96             [](void* context, struct address_block* block) {
97                 Stream* stream = reinterpret_cast<Stream*>(context);
98                 block->offset = stream->getBe64();
99                 block->size_available = stream->getBe64();
100             };
101         address_space_allocator_run(
102             &addr_alloc,
103             (void*)stream,
104             allocatorLoader,
105             allocatorBlockLoader);
106 
107         pageSize = stream->getBe64();
108         totalSize = stream->getBe64();
109         allocCount = stream->getBe32();
110 
111         return true;
112     }
113 
postLoad(void * postLoadBuffer)114     bool postLoad(void* postLoadBuffer) {
115         buffer = postLoadBuffer;
116         startAddr =
117             (uint64_t)(uintptr_t)postLoadBuffer;
118         return true;
119     }
120 
rangeCheck(const char * task,void * ptr)121     void rangeCheck(const char* task, void* ptr) {
122         uint64_t addr = (uintptr_t)ptr;
123         if (addr < startAddr ||
124             addr > endAddr) {
125             std::stringstream ss;
126             ss << "SubAllocator " << task << ": ";
127             ss << "Out of range: " << std::hex << addr << " ";
128             ss << "Range: " <<
129                 std::hex << startAddr << " " <<
130                 std::hex << endAddr;
131             std::string msg = ss.str();
132             ALOGE("Fatal: %s\n", msg.c_str());
133         }
134     }
135 
getOffset(void * checkedPtr)136     uint64_t getOffset(void* checkedPtr) {
137         uint64_t addr = (uintptr_t)checkedPtr;
138         return addr - startAddr;
139     }
140 
free(void * ptr)141     bool free(void* ptr) {
142         if (!ptr) return false;
143 
144         rangeCheck("free", ptr);
145         if (EINVAL == address_space_allocator_deallocate(
146             &addr_alloc, getOffset(ptr))) {
147             return false;
148         }
149 
150         --allocCount;
151         return true;
152     }
153 
freeAll()154     void freeAll() {
155         address_space_allocator_reset(&addr_alloc);
156         allocCount = 0;
157     }
158 
alloc(size_t wantedSize)159     void* alloc(size_t wantedSize) {
160         if (wantedSize == 0) return nullptr;
161 
162         uint64_t wantedSize64 =
163             (uint64_t)wantedSize;
164 
165         size_t toPageSize =
166             pageSize *
167             ((wantedSize + pageSize - 1) / pageSize);
168 
169         uint64_t offset =
170             address_space_allocator_allocate(
171                 &addr_alloc, toPageSize);
172 
173         if (offset == ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET) {
174             return nullptr;
175         }
176 
177         ++allocCount;
178         return (void*)(uintptr_t)(startAddr + offset);
179     }
180 
empty() const181     bool empty() const {
182         return allocCount == 0;
183     }
184 
185     void* buffer;
186     uint64_t totalSize;
187     uint64_t pageSize;
188     uint64_t startAddr;
189     uint64_t endAddr;
190     struct address_space_allocator addr_alloc;
191     uint32_t allocCount = 0;
192 };
193 
SubAllocator(void * buffer,uint64_t totalSize,uint64_t pageSize)194 SubAllocator::SubAllocator(
195     void* buffer,
196     uint64_t totalSize,
197     uint64_t pageSize) :
198     mImpl(
199         new SubAllocator::Impl(buffer, totalSize, pageSize)) { }
200 
~SubAllocator()201 SubAllocator::~SubAllocator() {
202     delete mImpl;
203 }
204 
205 // Snapshotting
save(Stream * stream)206 bool SubAllocator::save(Stream* stream) {
207     return mImpl->save(stream);
208 }
209 
load(Stream * stream)210 bool SubAllocator::load(Stream* stream) {
211     return mImpl->load(stream);
212 }
213 
postLoad(void * postLoadBuffer)214 bool SubAllocator::postLoad(void* postLoadBuffer) {
215     return mImpl->postLoad(postLoadBuffer);
216 }
217 
alloc(size_t wantedSize)218 void* SubAllocator::alloc(size_t wantedSize) {
219     return mImpl->alloc(wantedSize);
220 }
221 
free(void * ptr)222 bool SubAllocator::free(void* ptr) {
223     return mImpl->free(ptr);
224 }
225 
freeAll()226 void SubAllocator::freeAll() {
227     mImpl->freeAll();
228 }
229 
getOffset(void * ptr)230 uint64_t SubAllocator::getOffset(void* ptr) {
231     return mImpl->getOffset(ptr);
232 }
233 
empty() const234 bool SubAllocator::empty() const {
235     return mImpl->empty();
236 }
237 
238 } // namespace guest
239 } // namespace base
240 } // namespace android
241