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