1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 // This file defines partition_get_root().
6 #define ROOTVM_INIT 1
7
8 #include <assert.h>
9 #include <hyptypes.h>
10 #include <stdalign.h>
11 #include <string.h>
12
13 #include <allocator.h>
14 #include <atomic.h>
15 #include <attributes.h>
16 #include <bootmem.h>
17 #include <memdb.h>
18 #include <object.h>
19 #include <panic.h>
20 #include <partition.h>
21 #include <partition_alloc.h>
22 #include <partition_init.h>
23 #include <platform_mem.h>
24 #include <refcount.h>
25 #include <util.h>
26
27 #include <events/allocator.h>
28 #include <events/partition.h>
29
30 #include <asm/cpu.h>
31
32 #include "event_handlers.h"
33
34 static partition_t hyp_partition;
35 static partition_t *root_partition;
36
37 extern const char image_virt_start;
38 extern const char image_virt_last;
39 extern const char image_phys_start;
40 extern const char image_phys_last;
41
42 static const uintptr_t virt_start = (uintptr_t)&image_virt_start;
43 static const paddr_t phys_start = (paddr_t)&image_phys_start;
44 static const paddr_t phys_last = (paddr_t)&image_phys_last;
45
46 #if defined(ARCH_ARM) && ARCH_IS_64BIT
47 // Ensure hypervisor is 2MiB page size aligned to use AArch64 2M block mappings
48 static_assert(((size_t)PLATFORM_RW_DATA_SIZE & 0x1fffffU) == 0U,
49 "PLATFORM_RW_DATA_SIZE must be 2MB aligned");
50 static_assert(((size_t)PLATFORM_HEAP_PRIVATE_SIZE & 0xfffU) == 0U,
51 "PLATFORM_HEAP_PRIVATE_SIZE must be 4KB aligned");
52 #endif
53
54 void NOINLINE
partition_standard_handle_boot_cold_init(void)55 partition_standard_handle_boot_cold_init(void)
56 {
57 // Set up the hyp partition's header.
58 refcount_init(&hyp_partition.header.refcount);
59 hyp_partition.header.type = OBJECT_TYPE_PARTITION;
60 atomic_store_release(&hyp_partition.header.state, OBJECT_STATE_ACTIVE);
61
62 paddr_t hyp_heap_end =
63 (phys_last + 1U) - ((size_t)PLATFORM_RW_DATA_SIZE -
64 (size_t)PLATFORM_HEAP_PRIVATE_SIZE);
65 // Add hypervisor memory as a mapped range.
66 hyp_partition.mapped_ranges[0].virt = virt_start;
67 hyp_partition.mapped_ranges[0].phys = phys_start;
68 hyp_partition.mapped_ranges[0].size =
69 (size_t)(hyp_heap_end - phys_start);
70
71 // Allocate management structures for the hypervisor allocator.
72 if (allocator_init(&hyp_partition.allocator) != OK) {
73 panic("allocator_init() failed for hyp partition");
74 }
75
76 // Configure partition to be privileged
77 partition_option_flags_set_privileged(&hyp_partition.options, true);
78
79 // Get remaining boot memory and assign it to hypervisor allocator.
80 size_t hyp_alloc_size;
81 void_ptr_result_t ret = bootmem_allocate_remaining(&hyp_alloc_size);
82 if (ret.e != OK) {
83 panic("no boot mem");
84 }
85
86 paddr_t phys = partition_virt_to_phys(&hyp_partition, (uintptr_t)ret.r);
87 assert(phys != PADDR_INVALID);
88
89 error_t err = trigger_allocator_add_ram_range_event(
90 &hyp_partition, phys, (uintptr_t)ret.r, hyp_alloc_size);
91 if (err != OK) {
92 panic("Error moving bootmem to hyp_partition allocator");
93 }
94 }
95
96 void NOINLINE
partition_standard_boot_add_private_heap(void)97 partition_standard_boot_add_private_heap(void)
98 {
99 // Only the first 2MiB of RW data was mapped in the assembly mmu_init.
100 // The remainder is mapped by hyp_aspace_handle_boot_cold_init. Because
101 // of this, the additional memory if any needs to be added to the
102 // hyp_partition allocator here.
103 if ((size_t)PLATFORM_HEAP_PRIVATE_SIZE > 0x200000U) {
104 size_t remaining_size =
105 (size_t)PLATFORM_HEAP_PRIVATE_SIZE - 0x200000U;
106 paddr_t remaining_phys =
107 (phys_last + 1U) -
108 ((size_t)PLATFORM_RW_DATA_SIZE - 0x200000U);
109
110 error_t err = partition_add_heap(&hyp_partition, remaining_phys,
111 remaining_size);
112 if (err != OK) {
113 panic("Error expanding hyp_partition allocator");
114 }
115 }
116 }
117
118 static void
partition_add_ram(partition_t * partition,paddr_t base,size_t size)119 partition_add_ram(partition_t *partition, paddr_t base, size_t size)
120 {
121 error_t err;
122
123 #if defined(MODULE_MEM_MEMDB_GPT)
124 // Add the ram range to the memory database.
125 // FIXME:
126 err = memdb_insert(&hyp_partition, base, base + (size - 1U),
127 (uintptr_t)partition, MEMDB_TYPE_PARTITION_NOMAP);
128 if (err != OK) {
129 panic("Error inserting ram to memdb");
130 }
131 #endif
132
133 // Notify modules about new ram. Memdb type for this range will be
134 // updated to MEMDB_TYPE_PARTITION.
135 err = trigger_partition_add_ram_range_event(partition, base, size);
136 if (err != OK) {
137 panic("Error adding ram to partition");
138 }
139 }
140
141 void
partition_standard_handle_boot_hypervisor_start(void)142 partition_standard_handle_boot_hypervisor_start(void)
143 {
144 // Allocate root partition from the hypervisor allocator
145 partition_ptr_result_t part_ret = partition_allocate_partition(
146 &hyp_partition, (partition_create_t){ 0 });
147 if (part_ret.e != OK) {
148 panic("Error allocating root partition");
149 }
150 root_partition = (partition_t *)part_ret.r;
151
152 partition_option_flags_set_privileged(&root_partition->options, true);
153
154 if (object_activate_partition(root_partition) != OK) {
155 panic("Error activating root partition");
156 }
157
158 error_t err = platform_ram_probe();
159 if (err != OK) {
160 panic("Platform RAM probe failed");
161 }
162
163 platform_ram_info_t *ram_info = platform_get_ram_info();
164 assert(ram_info != NULL);
165
166 for (index_t i = 0U; i < ram_info->num_ranges; i++) {
167 paddr_t rbase = ram_info->ram_range[i].base;
168 size_t rsize = ram_info->ram_range[i].size;
169
170 assert(rsize != 0U);
171 assert(!util_add_overflows(rbase, rsize - 1U));
172
173 paddr_t rlast = rbase + (rsize - 1U);
174
175 if ((phys_start > rbase) && (phys_start <= rlast)) {
176 // Hyp image starts within the range; add the partial
177 // range before the start of the hyp image
178 partition_add_ram(root_partition, rbase,
179 (size_t)(phys_start - rbase));
180 }
181
182 if ((phys_last >= rbase) && (phys_last < rlast)) {
183 // Hyp image ends within the range, add the partial
184 // range after the end of the hyp image
185 partition_add_ram(root_partition, phys_last + 1U,
186 (size_t)(rlast - phys_last));
187 }
188
189 if ((phys_last < rbase) || (phys_start > rlast)) {
190 // No overlap with hyp image; add the entire range
191 partition_add_ram(root_partition, rbase, rsize);
192 }
193 }
194 }
195
196 partition_t *
partition_get_private(void)197 partition_get_private(void)
198 {
199 return &hyp_partition;
200 }
201
202 partition_t *
partition_get_root(void)203 partition_get_root(void)
204 {
205 return root_partition;
206 }
207