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