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