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