1 /*
2 * Copyright 2018 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
9 #include "hf/arch/init.h"
10
11 #include <stdalign.h>
12 #include <stddef.h>
13
14 #include "hf/arch/other_world.h"
15 #include "hf/arch/plat/ffa.h"
16
17 #include "hf/api.h"
18 #include "hf/boot_flow.h"
19 #include "hf/boot_params.h"
20 #include "hf/cpio.h"
21 #include "hf/cpu.h"
22 #include "hf/dlog.h"
23 #include "hf/fdt_handler.h"
24 #include "hf/load.h"
25 #include "hf/manifest.h"
26 #include "hf/mm.h"
27 #include "hf/mpool.h"
28 #include "hf/panic.h"
29 #include "hf/plat/boot_flow.h"
30 #include "hf/plat/console.h"
31 #include "hf/plat/interrupts.h"
32 #include "hf/plat/iommu.h"
33 #include "hf/std.h"
34 #include "hf/vm.h"
35
36 #include "vmapi/hf/call.h"
37
38 alignas(MM_PPOOL_ENTRY_SIZE) char ptable_buf[MM_PPOOL_ENTRY_SIZE * HEAP_PAGES];
39
40 static struct mpool ppool;
41
42 /**
43 * Performs one-time initialisation of memory management for the hypervisor.
44 *
45 * This is the only C code entry point called with MMU and caching disabled. The
46 * page table returned is used to set up the MMU and caches for all subsequent
47 * code.
48 */
one_time_init_mm(void)49 void one_time_init_mm(void)
50 {
51 /* Make sure the console is initialised before calling dlog. */
52 plat_console_init();
53
54 plat_ffa_log_init();
55
56 mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
57 mpool_add_chunk(&ppool, ptable_buf, sizeof(ptable_buf));
58
59 if (!mm_init(&ppool)) {
60 panic("mm_init failed");
61 }
62 }
63
64 /**
65 * Performs one-time initialisation of the hypervisor.
66 */
one_time_init(void)67 void one_time_init(void)
68 {
69 struct string manifest_fname = STRING_INIT("manifest.dtb");
70 struct fdt fdt;
71 enum manifest_return_code manifest_ret;
72 struct boot_params *params;
73 struct boot_params_update update;
74 struct memiter cpio;
75 struct memiter manifest_it;
76 void *initrd;
77 size_t i;
78 struct mm_stage1_locked mm_stage1_locked;
79 struct manifest *manifest;
80
81 arch_one_time_init();
82
83 /* Enable locks now that mm is initialised. */
84 dlog_enable_lock();
85 mpool_enable_locks();
86
87 mm_stage1_locked = mm_lock_stage1();
88
89 if (!fdt_map(&fdt, mm_stage1_locked, plat_boot_flow_get_fdt_addr(),
90 &ppool)) {
91 panic("Unable to map FDT.");
92 }
93
94 static_assert(sizeof(struct boot_params) <= MM_PPOOL_ENTRY_SIZE,
95 "The sizeof boot params must fit an entry of the mpool.");
96 params = (struct boot_params *)mpool_alloc(&ppool);
97
98 if (params == NULL) {
99 panic("Could not use memory pool to allocate boot params.");
100 }
101
102 if (!boot_flow_get_params(params, &fdt)) {
103 panic("Could not parse boot params.");
104 }
105
106 for (i = 0; i < params->mem_ranges_count; ++i) {
107 dlog_info("Memory range: %#lx - %#lx\n",
108 pa_addr(params->mem_ranges[i].begin),
109 pa_addr(params->mem_ranges[i].end) - 1);
110 }
111
112 /*
113 * Hafnium manifest is either gathered from the ramdisk or passed
114 * directly to Hafnium entry point by the earlier bootloader stage.
115 * If the ramdisk start address is non-zero it hints the manifest
116 * shall be looked up from the ramdisk. If zero, assume the address
117 * passed to Hafnium entry point is the manifest address.
118 */
119 if (pa_addr(params->initrd_begin)) {
120 dlog_info("Ramdisk range: %#lx - %#lx\n",
121 pa_addr(params->initrd_begin),
122 pa_addr(params->initrd_end) - 1);
123
124 /* Map initrd in, and initialise cpio parser. */
125 initrd = mm_identity_map(mm_stage1_locked, params->initrd_begin,
126 params->initrd_end, MM_MODE_R, &ppool);
127 if (!initrd) {
128 panic("Unable to map initrd.");
129 }
130
131 memiter_init(&cpio, initrd,
132 pa_difference(params->initrd_begin,
133 params->initrd_end));
134
135 if (!cpio_get_file(&cpio, &manifest_fname, &manifest_it)) {
136 panic("Could not find manifest in initrd.");
137 }
138 } else {
139 manifest_it = fdt.buf;
140 }
141
142 dlog_verbose("Manifest range: %p - %p (%ld bytes)\n",
143 (void *)manifest_it.next, (void *)manifest_it.limit,
144 manifest_it.limit - manifest_it.next);
145 if (!is_aligned(manifest_it.next, 4)) {
146 panic("Manifest not aligned.");
147 }
148
149 manifest_ret = manifest_init(mm_stage1_locked, &manifest, &manifest_it,
150 params, &ppool);
151
152 if (manifest_ret != MANIFEST_SUCCESS) {
153 panic("Could not parse manifest: %s.",
154 manifest_strerror(manifest_ret));
155 }
156
157 plat_ffa_set_tee_enabled(manifest->ffa_tee_enabled);
158
159 if (!plat_iommu_init(&fdt, mm_stage1_locked, &ppool)) {
160 panic("Could not initialize IOMMUs.");
161 }
162
163 cpu_module_init(params->cpu_ids, params->cpu_count);
164
165 if (!plat_interrupts_controller_driver_init(&fdt, mm_stage1_locked,
166 &ppool)) {
167 panic("Could not initialize Interrupt Controller driver.");
168 }
169
170 if (!fdt_unmap(&fdt, mm_stage1_locked, &ppool)) {
171 panic("Unable to unmap FDT.");
172 }
173
174 /* Load all VMs. */
175 update.reserved_ranges_count = 0;
176 if (!load_vms(mm_stage1_locked, manifest, &cpio, params, &update,
177 &ppool)) {
178 panic("Unable to load VMs.");
179 }
180
181 if (!boot_flow_update(mm_stage1_locked, manifest, &update, &cpio,
182 &ppool)) {
183 panic("Unable to update boot flow.");
184 }
185
186 /* Free space allocated for the boot parameters. */
187 mpool_free(&ppool, params);
188
189 /* Now manifest parsing has completed free the resourses used. */
190 manifest_deinit(&ppool);
191
192 mm_unlock_stage1(&mm_stage1_locked);
193
194 /* Enable TLB invalidation for VM page table updates. */
195 mm_vm_enable_invalidation();
196
197 /* Perform platform specfic FF-A initialization. */
198 plat_ffa_init(&ppool);
199
200 /* Initialise the API page pool. ppool will be empty from now on. */
201 api_init(&ppool);
202
203 dlog_info("Hafnium initialisation completed\n");
204 }
205