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