1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 #include <assert.h>
6 #include <hyptypes.h>
7
8 #include <bootmem.h>
9 #include <util.h>
10
11 #include "event_handlers.h"
12
13 static bootmem_allocator_t bootmem_allocator;
14
15 // For now the hypervisor private heap is statically defined in the linker
16 // script. The intention is to replace this with dynamically determined memory -
17 // such as through boot configuration structures.
18 extern uint8_t heap_private_start;
19 extern uint8_t heap_private_end;
20 extern uint8_t image_virt_end;
21
22 void
allocator_boot_handle_boot_runtime_first_init(void)23 allocator_boot_handle_boot_runtime_first_init(void)
24 {
25 assert((uintptr_t)&heap_private_end > (uintptr_t)&heap_private_start);
26
27 static_assert(
28 PLATFORM_HEAP_PRIVATE_SIZE <= PLATFORM_RW_DATA_SIZE,
29 "PLATFORM_HEAP_PRIVATE_SIZE must be <= PLATFORM_RW_DATA_SIZE");
30 static_assert(PLATFORM_RW_DATA_SIZE >= 0x200000,
31 "PLATFORM_RW_DATA_SIZE must be >= 2MB");
32
33 // We only give heap within the first 2MB RW page to the bootmem. We
34 // will map the rest of the heap during the hyp_aspace init.
35 void *base = &heap_private_start;
36 uintptr_t map_end = util_balign_up((uintptr_t)base, 0x200000U);
37
38 uintptr_t hyp_priv_end =
39 (((uintptr_t)&image_virt_end) - (size_t)PLATFORM_RW_DATA_SIZE) +
40 (size_t)PLATFORM_HEAP_PRIVATE_SIZE;
41 uintptr_t end = util_min(map_end, hyp_priv_end);
42
43 assert((uintptr_t)base < end);
44 size_t size = end - (uintptr_t)base;
45
46 assert(base != NULL);
47 assert(size >= 0x1000U);
48
49 bootmem_allocator.pool_base = (uint8_t *)base;
50 bootmem_allocator.pool_size = size;
51 bootmem_allocator.alloc_offset = 0;
52 }
53
54 void_ptr_result_t
bootmem_allocate(size_t size,size_t align)55 bootmem_allocate(size_t size, size_t align)
56 {
57 assert(bootmem_allocator.alloc_offset <= bootmem_allocator.pool_size);
58 uintptr_t loc = (uintptr_t)bootmem_allocator.pool_base;
59
60 assert(!util_add_overflows(loc, bootmem_allocator.alloc_offset));
61 loc += bootmem_allocator.alloc_offset;
62
63 if (!util_is_p2_or_zero(align)) {
64 return void_ptr_result_error(ERROR_ARGUMENT_ALIGNMENT);
65 }
66 if (util_is_p2(align)) {
67 loc = util_balign_up(loc, align);
68 }
69
70 size_t free_boot = bootmem_allocator.pool_size -
71 (loc - (uintptr_t)bootmem_allocator.pool_base);
72
73 if (size > free_boot) {
74 return void_ptr_result_error(ERROR_NOMEM);
75 }
76
77 bootmem_allocator.alloc_offset =
78 (loc - (uintptr_t)bootmem_allocator.pool_base + size);
79
80 return void_ptr_result_ok((void *)loc);
81 }
82
83 void_ptr_result_t
bootmem_allocate_remaining(size_t * size)84 bootmem_allocate_remaining(size_t *size)
85 {
86 assert(size != NULL);
87
88 assert(bootmem_allocator.alloc_offset <= bootmem_allocator.pool_size);
89 size_t free_boot =
90 bootmem_allocator.pool_size - bootmem_allocator.alloc_offset;
91 if (free_boot == 0U) {
92 return void_ptr_result_error(ERROR_NOMEM);
93 }
94 *size = free_boot;
95
96 uintptr_t loc = (uintptr_t)bootmem_allocator.pool_base;
97 assert(!util_add_overflows(loc, bootmem_allocator.alloc_offset));
98 loc += bootmem_allocator.alloc_offset;
99
100 bootmem_allocator.alloc_offset = bootmem_allocator.pool_size;
101
102 return void_ptr_result_ok((void *)loc);
103 }
104
105 void *
bootmem_get_region(size_t * size)106 bootmem_get_region(size_t *size)
107 {
108 *size = bootmem_allocator.pool_size;
109 return bootmem_allocator.pool_base;
110 }
111