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/mm.h"
26 #include "hf/mpool.h"
27 #include "hf/panic.h"
28 #include "hf/plat/boot_flow.h"
29 #include "hf/plat/console.h"
30 #include "hf/plat/interrupts.h"
31 #include "hf/plat/iommu.h"
32 #include "hf/std.h"
33 #include "hf/vm.h"
34
35 #include "vmapi/hf/call.h"
36
37 alignas(MM_PPOOL_ENTRY_SIZE) char ptable_buf[MM_PPOOL_ENTRY_SIZE * HEAP_PAGES];
38
39 static struct mpool ppool;
40
41 /**
42 * Performs one-time initialisation of memory management for the hypervisor.
43 *
44 * This is the only C code entry point called with MMU and caching disabled. The
45 * page table returned is used to set up the MMU and caches for all subsequent
46 * code.
47 */
one_time_init_mm(void)48 void one_time_init_mm(void)
49 {
50 /* Make sure the console is initialised before calling dlog. */
51 plat_console_init();
52
53 plat_ffa_log_init();
54
55 mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
56 mpool_add_chunk(&ppool, ptable_buf, sizeof(ptable_buf));
57
58 if (!mm_init(&ppool)) {
59 panic("mm_init failed");
60 }
61 }
62
63 /**
64 * Performs one-time initialisation of the hypervisor.
65 */
one_time_init(void)66 void one_time_init(void)
67 {
68 struct string manifest_fname = STRING_INIT("manifest.dtb");
69 struct fdt fdt;
70 enum manifest_return_code manifest_ret;
71 struct boot_params params;
72 struct boot_params_update update;
73 struct memiter cpio;
74 struct memiter manifest_it;
75 void *initrd;
76 size_t i;
77 struct mm_stage1_locked mm_stage1_locked;
78 struct manifest *manifest;
79
80 arch_one_time_init();
81
82 /* Enable locks now that mm is initialised. */
83 dlog_enable_lock();
84 mpool_enable_locks();
85
86 mm_stage1_locked = mm_lock_stage1();
87
88 if (!fdt_map(&fdt, mm_stage1_locked, plat_boot_flow_get_fdt_addr(),
89 &ppool)) {
90 panic("Unable to map FDT.");
91 }
92
93 if (!boot_flow_get_params(¶ms, &fdt)) {
94 panic("Could not parse boot params.");
95 }
96
97 for (i = 0; i < params.mem_ranges_count; ++i) {
98 dlog_info("Memory range: %#x - %#x\n",
99 pa_addr(params.mem_ranges[i].begin),
100 pa_addr(params.mem_ranges[i].end) - 1);
101 }
102
103 /*
104 * Hafnium manifest is either gathered from the ramdisk or passed
105 * directly to Hafnium entry point by the earlier bootloader stage.
106 * If the ramdisk start address is non-zero it hints the manifest
107 * shall be looked up from the ramdisk. If zero, assume the address
108 * passed to Hafnium entry point is the manifest address.
109 */
110 if (pa_addr(params.initrd_begin)) {
111 dlog_info("Ramdisk range: %#x - %#x\n",
112 pa_addr(params.initrd_begin),
113 pa_addr(params.initrd_end) - 1);
114
115 /* Map initrd in, and initialise cpio parser. */
116 initrd = mm_identity_map(mm_stage1_locked, params.initrd_begin,
117 params.initrd_end, MM_MODE_R, &ppool);
118 if (!initrd) {
119 panic("Unable to map initrd.");
120 }
121
122 memiter_init(
123 &cpio, initrd,
124 pa_difference(params.initrd_begin, params.initrd_end));
125
126 if (!cpio_get_file(&cpio, &manifest_fname, &manifest_it)) {
127 panic("Could not find manifest in initrd.");
128 }
129 } else {
130 manifest_it = fdt.buf;
131 }
132
133 manifest_ret = manifest_init(mm_stage1_locked, &manifest, &manifest_it,
134 &ppool);
135
136 if (manifest_ret != MANIFEST_SUCCESS) {
137 panic("Could not parse manifest: %s.",
138 manifest_strerror(manifest_ret));
139 }
140
141 plat_ffa_set_tee_enabled(manifest->ffa_tee_enabled);
142
143 if (!plat_iommu_init(&fdt, mm_stage1_locked, &ppool)) {
144 panic("Could not initialize IOMMUs.");
145 }
146
147 if (!fdt_unmap(&fdt, mm_stage1_locked, &ppool)) {
148 panic("Unable to unmap FDT.");
149 }
150
151 cpu_module_init(params.cpu_ids, params.cpu_count);
152
153 if (!plat_interrupts_controller_driver_init(&fdt, mm_stage1_locked,
154 &ppool)) {
155 panic("Could not initialize Interrupt Controller driver.");
156 }
157
158 /* Load all VMs. */
159 update.reserved_ranges_count = 0;
160 if (!load_vms(mm_stage1_locked, manifest, &cpio, ¶ms, &update,
161 &ppool)) {
162 panic("Unable to load VMs.");
163 }
164
165 if (!boot_flow_update(mm_stage1_locked, manifest, &update, &cpio,
166 &ppool)) {
167 panic("Unable to update boot flow.");
168 }
169
170 /* Now manifest parsing has completed free the resourses used. */
171 manifest_deinit(&ppool);
172
173 mm_unlock_stage1(&mm_stage1_locked);
174
175 /* Enable TLB invalidation for VM page table updates. */
176 mm_vm_enable_invalidation();
177
178 /* Perform platform specfic FF-A initialization. */
179 plat_ffa_init(&ppool);
180
181 /* Initialise the API page pool. ppool will be empty from now on. */
182 api_init(&ppool);
183
184 dlog_info("Hafnium initialisation completed\n");
185 }
186