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(&params, &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, &params, &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