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 #pragma once
15
16 #include "android/utils/compiler.h"
17 #include <assert.h>
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 ANDROID_BEGIN_HEADER
25
26 #ifdef ADDRESS_SPACE_NAMESPACE
27 namespace ADDRESS_SPACE_NAMESPACE {
28 #endif
29
30 // This is ported from goldfish_address_space, allowing it to be used for
31 // general sub-allocations of any buffer range.
32 // It is also a pure header library, so there are no compiler tricks needed
33 // to use this in a particular implementation. please don't include this
34 // in a file that is included everywhere else, though.
35
36 /* Represents a continuous range of addresses and a flag if this block is
37 * available
38 */
39 struct address_block {
40 uint64_t offset;
41 union {
42 uint64_t size_available; /* VMSTATE_x does not support bit fields */
43 struct {
44 uint64_t size : 63;
45 uint64_t available : 1;
46 };
47 };
48 };
49
50 /* A dynamic array of address blocks, with the following invariant:
51 * blocks[i].size > 0
52 * blocks[i+1].offset = blocks[i].offset + blocks[i].size
53 */
54 struct address_space_allocator {
55 struct address_block *blocks;
56 int size;
57 int capacity;
58 uint64_t total_bytes;
59 };
60
61 #define ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET (~(uint64_t)0)
62 #define ANDROID_EMU_ADDRESS_SPACE_DEFAULT_PAGE_SIZE 4096
63
64 /* The assert function to abort if something goes wrong. */
address_space_assert(bool condition)65 static void address_space_assert(bool condition) {
66 #ifdef ANDROID_EMU_ADDRESS_SPACE_ASSERT_FUNC
67 ANDROID_EMU_ADDRESS_SPACE_ASSERT_FUNC(condition);
68 #else
69 assert(condition);
70 #endif
71 }
72
address_space_malloc0(size_t size)73 static void* address_space_malloc0(size_t size) {
74 #ifdef ANDROID_EMU_ADDRESS_SPACE_MALLOC0_FUNC
75 return ANDROID_EMU_ADDRESS_SPACE_MALLOC0_FUNC(size);
76 #else
77 void* res = malloc(size);
78 memset(res, 0, size);
79 return res;
80 #endif
81 }
82
address_space_realloc(void * ptr,size_t size)83 static void* address_space_realloc(void* ptr, size_t size) {
84 #ifdef ANDROID_EMU_ADDRESS_SPACE_REALLOC_FUNC
85 return ANDROID_EMU_ADDRESS_SPACE_REALLOC_FUNC(ptr, size);
86 #else
87 void* res = realloc(ptr, size);
88 return res;
89 #endif
90 }
91
address_space_free(void * ptr)92 static void address_space_free(void* ptr) {
93 #ifdef ANDROID_EMU_ADDRESS_SPACE_FREE_FUNC
94 return ANDROID_EMU_ADDRESS_SPACE_FREE_FUNC(ptr);
95 #else
96 free(ptr);
97 #endif
98 }
99
100 /* Looks for the smallest (to reduce fragmentation) available block with size to
101 * fit the requested amount and returns its index or -1 if none is available.
102 */
address_space_allocator_find_available_block(struct address_block * block,int n_blocks,uint64_t size_at_least)103 static int address_space_allocator_find_available_block(
104 struct address_block *block,
105 int n_blocks,
106 uint64_t size_at_least)
107 {
108 int index = -1;
109 uint64_t size_at_index = 0;
110 int i;
111
112 address_space_assert(n_blocks >= 1);
113
114 for (i = 0; i < n_blocks; ++i, ++block) {
115 uint64_t this_size = block->size;
116 address_space_assert(this_size > 0);
117
118 if (this_size >= size_at_least && block->available &&
119 (index < 0 || this_size < size_at_index)) {
120 index = i;
121 size_at_index = this_size;
122 }
123 }
124
125 return index;
126 }
127
128 static int
address_space_allocator_grow_capacity(int old_capacity)129 address_space_allocator_grow_capacity(int old_capacity) {
130 address_space_assert(old_capacity >= 1);
131
132 return old_capacity + old_capacity;
133 }
134
135 /* Inserts one more address block right after i'th (by borrowing i'th size) and
136 * adjusts sizes:
137 * pre:
138 * size > blocks[i].size
139 *
140 * post:
141 * * might reallocate allocator->blocks if there is no capacity to insert one
142 * * blocks[i].size -= size;
143 * * blocks[i+1].size = size;
144 */
145 static struct address_block*
address_space_allocator_split_block(struct address_space_allocator * allocator,int i,uint64_t size)146 address_space_allocator_split_block(
147 struct address_space_allocator *allocator,
148 int i,
149 uint64_t size)
150 {
151 address_space_assert(allocator->capacity >= 1);
152 address_space_assert(allocator->size >= 1);
153 address_space_assert(allocator->size <= allocator->capacity);
154 address_space_assert(i >= 0);
155 address_space_assert(i < allocator->size);
156 address_space_assert(size < allocator->blocks[i].size);
157
158 if (allocator->size == allocator->capacity) {
159 int new_capacity = address_space_allocator_grow_capacity(allocator->capacity);
160 allocator->blocks =
161 (struct address_block*)
162 address_space_realloc(
163 allocator->blocks,
164 sizeof(struct address_block) * new_capacity);
165 address_space_assert(allocator->blocks);
166 allocator->capacity = new_capacity;
167 }
168
169 struct address_block *blocks = allocator->blocks;
170
171 /* size = 5, i = 1
172 * [ 0 | 1 | 2 | 3 | 4 ] => [ 0 | 1 | new | 2 | 3 | 4 ]
173 * i (i+1) (i+2) i (i+1) (i+2)
174 */
175 memmove(&blocks[i + 2], &blocks[i + 1],
176 sizeof(struct address_block) * (allocator->size - i - 1));
177
178 struct address_block *to_borrow_from = &blocks[i];
179 struct address_block *new_block = to_borrow_from + 1;
180
181 uint64_t new_size = to_borrow_from->size - size;
182
183 to_borrow_from->size = new_size;
184
185 new_block->offset = to_borrow_from->offset + new_size;
186 new_block->size = size;
187 new_block->available = 1;
188
189 ++allocator->size;
190
191 return new_block;
192 }
193
194 /* Marks i'th block as available. If adjacent ((i-1) and (i+1)) blocks are also
195 * available, it merges i'th block with them.
196 * pre:
197 * i < allocator->size
198 * post:
199 * i'th block is merged with adjacent ones if they are available, blocks that
200 * were merged from are removed. allocator->size is updated if blocks were
201 * removed.
202 */
address_space_allocator_release_block(struct address_space_allocator * allocator,int i)203 static void address_space_allocator_release_block(
204 struct address_space_allocator *allocator,
205 int i)
206 {
207 struct address_block *blocks = allocator->blocks;
208 int before = i - 1;
209 int after = i + 1;
210 int size = allocator->size;
211
212 address_space_assert(i >= 0);
213 address_space_assert(i < size);
214
215 blocks[i].available = 1;
216
217 if (before >= 0 && blocks[before].available) {
218 if (after < size && blocks[after].available) {
219 // merge (before, i, after) into before
220 blocks[before].size += (blocks[i].size + blocks[after].size);
221
222 size -= 2;
223 memmove(&blocks[i], &blocks[i + 2],
224 sizeof(struct address_block) * (size - i));
225 allocator->size = size;
226 } else {
227 // merge (before, i) into before
228 blocks[before].size += blocks[i].size;
229
230 --size;
231 memmove(&blocks[i], &blocks[i + 1],
232 sizeof(struct address_block) * (size - i));
233 allocator->size = size;
234 }
235 } else if (after < size && blocks[after].available) {
236 // merge (i, after) into i
237 blocks[i].size += blocks[after].size;
238
239 --size;
240 memmove(&blocks[after], &blocks[after + 1],
241 sizeof(struct address_block) * (size - after));
242 allocator->size = size;
243 }
244
245 }
246
247 /* Takes a size to allocate an address block and returns an offset where this
248 * block is allocated. This block will not be available for other callers unless
249 * it is explicitly deallocated (see address_space_allocator_deallocate below).
250 */
address_space_allocator_allocate(struct address_space_allocator * allocator,uint64_t size)251 static uint64_t address_space_allocator_allocate(
252 struct address_space_allocator *allocator,
253 uint64_t size)
254 {
255 int i = address_space_allocator_find_available_block(allocator->blocks,
256 allocator->size,
257 size);
258 if (i < 0) {
259 return ANDROID_EMU_ADDRESS_SPACE_BAD_OFFSET;
260 } else {
261 address_space_assert(i < allocator->size);
262
263 struct address_block *block = &allocator->blocks[i];
264 address_space_assert(block->size >= size);
265
266 if (block->size > size) {
267 block = address_space_allocator_split_block(allocator, i, size);
268 }
269
270 address_space_assert(block->size == size);
271 block->available = 0;
272
273 return block->offset;
274 }
275 }
276
277 /* Takes an offset returned from address_space_allocator_allocate ealier
278 * (see above) and marks this block as available for further allocation.
279 */
address_space_allocator_deallocate(struct address_space_allocator * allocator,uint64_t offset)280 static uint32_t address_space_allocator_deallocate(
281 struct address_space_allocator *allocator,
282 uint64_t offset)
283 {
284 struct address_block *block = allocator->blocks;
285 int size = allocator->size;
286 int i;
287
288 address_space_assert(size >= 1);
289
290 for (i = 0; i < size; ++i, ++block) {
291 if (block->offset == offset) {
292 if (block->available) {
293 return EINVAL;
294 } else {
295 address_space_allocator_release_block(allocator, i);
296 return 0;
297 }
298 }
299 }
300
301 return EINVAL;
302 }
303
304 /* Creates a seed block. */
address_space_allocator_init(struct address_space_allocator * allocator,uint64_t size,int initial_capacity)305 static void address_space_allocator_init(
306 struct address_space_allocator *allocator,
307 uint64_t size,
308 int initial_capacity)
309 {
310 address_space_assert(initial_capacity >= 1);
311
312 allocator->blocks =
313 (struct address_block*)
314 malloc(sizeof(struct address_block) * initial_capacity);
315 memset(allocator->blocks, 0, sizeof(struct address_block) * initial_capacity);
316 address_space_assert(allocator->blocks);
317
318 struct address_block *block = allocator->blocks;
319
320 block->offset = 0;
321 block->size = size;
322 block->available = 1;
323
324 allocator->size = 1;
325 allocator->capacity = initial_capacity;
326 allocator->total_bytes = size;
327 }
328
329 /* At this point there should be no used blocks and all available blocks must
330 * have been merged into one block.
331 */
address_space_allocator_destroy(struct address_space_allocator * allocator)332 static void address_space_allocator_destroy(
333 struct address_space_allocator *allocator)
334 {
335 address_space_assert(allocator->size == 1);
336 address_space_assert(allocator->capacity >= allocator->size);
337 address_space_assert(allocator->blocks[0].available);
338 address_space_free(allocator->blocks);
339 }
340
341 /* Destroy function if we don't care what was previoulsy allocated.
342 * have been merged into one block.
343 */
address_space_allocator_destroy_nocleanup(struct address_space_allocator * allocator)344 static void address_space_allocator_destroy_nocleanup(
345 struct address_space_allocator *allocator)
346 {
347 address_space_free(allocator->blocks);
348 }
349
350 /* Resets the state of the allocator to the initial state without
351 * performing any dynamic memory management. */
address_space_allocator_reset(struct address_space_allocator * allocator)352 static void address_space_allocator_reset(
353 struct address_space_allocator *allocator)
354 {
355 address_space_assert(allocator->size >= 1);
356
357 allocator->size = 1;
358
359 struct address_block* block = allocator->blocks;
360 block->offset = 0;
361 block->size = allocator->total_bytes;
362 block->available = 1;
363 }
364
365 typedef void (*address_block_iter_func_t)(void* context, struct address_block*);
366 typedef void (*address_space_allocator_iter_func_t)(void* context, struct address_space_allocator*);
367
address_space_allocator_run(struct address_space_allocator * allocator,void * context,address_space_allocator_iter_func_t allocator_func,address_block_iter_func_t block_func)368 static void address_space_allocator_run(
369 struct address_space_allocator *allocator,
370 void* context,
371 address_space_allocator_iter_func_t allocator_func,
372 address_block_iter_func_t block_func)
373 {
374 struct address_block *block = 0;
375 int size;
376 int i;
377
378 allocator_func(context, allocator);
379
380 block = allocator->blocks;
381 size = allocator->size;
382
383 address_space_assert(size >= 1);
384
385 for (i = 0; i < size; ++i, ++block) {
386 block_func(context, block);
387 }
388 }
389
390 #ifdef ADDRESS_SPACE_NAMESPACE
391 }
392 #endif
393
394 ANDROID_END_HEADER
395