blob: ccf496e2a0b225534baddb22a339859b5bfe0f28 [file] [log] [blame]
Andrew Scullb2910562019-09-17 14:08:27 +01001/*
2 * Copyright 2018 The Hafnium Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hf/arch/init.h"
18
19#include <stdalign.h>
20#include <stddef.h>
21
Andrew Walbran41a49d82020-01-10 17:46:38 +000022#include "hf/arch/tee.h"
23
Andrew Scullb2910562019-09-17 14:08:27 +010024#include "hf/api.h"
25#include "hf/boot_flow.h"
26#include "hf/boot_params.h"
27#include "hf/cpio.h"
28#include "hf/cpu.h"
29#include "hf/dlog.h"
Andrew Scull3c257452019-11-26 13:32:50 +000030#include "hf/fdt_handler.h"
Andrew Scullb2910562019-09-17 14:08:27 +010031#include "hf/load.h"
32#include "hf/mm.h"
33#include "hf/mpool.h"
34#include "hf/panic.h"
Andrew Scull3c257452019-11-26 13:32:50 +000035#include "hf/plat/boot_flow.h"
Andrew Scullb2910562019-09-17 14:08:27 +010036#include "hf/plat/console.h"
Andrew Scull3c257452019-11-26 13:32:50 +000037#include "hf/plat/iommu.h"
Andrew Scullb2910562019-09-17 14:08:27 +010038#include "hf/std.h"
39#include "hf/vm.h"
40
41#include "vmapi/hf/call.h"
42
Andrew Walbran5de9c3d2020-02-10 13:35:29 +000043alignas(MM_PPOOL_ENTRY_SIZE) char ptable_buf[MM_PPOOL_ENTRY_SIZE * HEAP_PAGES];
Andrew Scullb2910562019-09-17 14:08:27 +010044
45static struct mpool ppool;
46
47/**
48 * Performs one-time initialisation of memory management for the hypervisor.
49 *
50 * This is the only C code entry point called with MMU and caching disabled. The
51 * page table returned is used to set up the MMU and caches for all subsequent
52 * code.
53 */
54void one_time_init_mm(void)
55{
56 /* Make sure the console is initialised before calling dlog. */
57 plat_console_init();
58
Andrew Walbran17eebf92020-02-05 16:35:49 +000059 dlog_notice("Initialising hafnium\n");
Andrew Scullb2910562019-09-17 14:08:27 +010060
Andrew Walbran5de9c3d2020-02-10 13:35:29 +000061 mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
Andrew Scullb2910562019-09-17 14:08:27 +010062 mpool_add_chunk(&ppool, ptable_buf, sizeof(ptable_buf));
63
64 if (!mm_init(&ppool)) {
65 panic("mm_init failed");
66 }
67}
68
69/**
70 * Performs one-time initialisation of the hypervisor.
71 */
72void one_time_init(void)
73{
David Brazdila2358d42020-01-27 18:51:38 +000074 struct string manifest_fname = STRING_INIT("manifest.dtb");
David Brazdilb856be62020-03-25 10:14:55 +000075 struct fdt fdt;
Andrew Scullb2910562019-09-17 14:08:27 +010076 struct manifest manifest;
David Brazdila2358d42020-01-27 18:51:38 +000077 enum manifest_return_code manifest_ret;
Andrew Scullb2910562019-09-17 14:08:27 +010078 struct boot_params params;
79 struct boot_params_update update;
Andrew Scullb2910562019-09-17 14:08:27 +010080 struct memiter cpio;
David Brazdila2358d42020-01-27 18:51:38 +000081 struct memiter manifest_it;
Andrew Scullb2910562019-09-17 14:08:27 +010082 void *initrd;
83 size_t i;
84 struct mm_stage1_locked mm_stage1_locked;
85
86 arch_one_time_init();
87
88 /* Enable locks now that mm is initialised. */
89 dlog_enable_lock();
90 mpool_enable_locks();
91
92 mm_stage1_locked = mm_lock_stage1();
93
David Brazdilb856be62020-03-25 10:14:55 +000094 if (!fdt_map(&fdt, mm_stage1_locked, plat_boot_flow_get_fdt_addr(),
95 &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +000096 panic("Unable to map FDT.");
Andrew Scull3c257452019-11-26 13:32:50 +000097 }
98
David Brazdilb856be62020-03-25 10:14:55 +000099 if (!boot_flow_get_params(&params, &fdt)) {
David Brazdila2358d42020-01-27 18:51:38 +0000100 panic("Could not parse boot params.");
Andrew Scullb2910562019-09-17 14:08:27 +0100101 }
102
Andrew Scullb2910562019-09-17 14:08:27 +0100103 for (i = 0; i < params.mem_ranges_count; ++i) {
Andrew Walbran17eebf92020-02-05 16:35:49 +0000104 dlog_info("Memory range: %#x - %#x\n",
105 pa_addr(params.mem_ranges[i].begin),
106 pa_addr(params.mem_ranges[i].end) - 1);
Andrew Scullb2910562019-09-17 14:08:27 +0100107 }
108
Olivier Deprez62d99e32020-01-09 15:58:07 +0100109 /*
110 * Hafnium manifest is either gathered from the ramdisk or passed
111 * directly to Hafnium entry point by the earlier bootloader stage.
112 * If the ramdisk start address is non-zero it hints the manifest
113 * shall be looked up from the ramdisk. If zero, assume the address
114 * passed to Hafnium entry point is the manifest address.
115 */
116 if (pa_addr(params.initrd_begin)) {
117 dlog_info("Ramdisk range: %#x - %#x\n",
118 pa_addr(params.initrd_begin),
119 pa_addr(params.initrd_end) - 1);
Andrew Scullb2910562019-09-17 14:08:27 +0100120
Olivier Deprez62d99e32020-01-09 15:58:07 +0100121 /* Map initrd in, and initialise cpio parser. */
122 initrd = mm_identity_map(mm_stage1_locked, params.initrd_begin,
123 params.initrd_end, MM_MODE_R, &ppool);
124 if (!initrd) {
125 panic("Unable to map initrd.");
126 }
127
128 memiter_init(
129 &cpio, initrd,
130 pa_difference(params.initrd_begin, params.initrd_end));
131
132 if (!cpio_get_file(&cpio, &manifest_fname, &manifest_it)) {
133 panic("Could not find manifest in initrd.");
134 }
135 } else {
136 manifest_it = fdt.buf;
Andrew Scullb2910562019-09-17 14:08:27 +0100137 }
138
Olivier Deprez62d99e32020-01-09 15:58:07 +0100139 manifest_ret = manifest_init(mm_stage1_locked, &manifest, &manifest_it,
140 &ppool);
Andrew Scullb2910562019-09-17 14:08:27 +0100141
David Brazdila2358d42020-01-27 18:51:38 +0000142 if (manifest_ret != MANIFEST_SUCCESS) {
143 panic("Could not parse manifest: %s.",
144 manifest_strerror(manifest_ret));
145 }
146
David Brazdilb856be62020-03-25 10:14:55 +0000147 if (!plat_iommu_init(&fdt, mm_stage1_locked, &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +0000148 panic("Could not initialize IOMMUs.");
149 }
150
David Brazdilb856be62020-03-25 10:14:55 +0000151 if (!fdt_unmap(&fdt, mm_stage1_locked, &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +0000152 panic("Unable to unmap FDT.");
153 }
154
155 cpu_module_init(params.cpu_ids, params.cpu_count);
156
Andrew Scullb2910562019-09-17 14:08:27 +0100157 /* Load all VMs. */
Andrew Scullb2910562019-09-17 14:08:27 +0100158 update.reserved_ranges_count = 0;
Andrew Scull72b43c02019-09-18 13:53:45 +0100159 if (!load_vms(mm_stage1_locked, &manifest, &cpio, &params, &update,
160 &ppool)) {
161 panic("Unable to load VMs.");
Andrew Scullb2910562019-09-17 14:08:27 +0100162 }
163
David Brazdile6f83222019-09-23 14:47:37 +0100164 if (!boot_flow_update(mm_stage1_locked, &manifest, &update, &cpio,
165 &ppool)) {
Andrew Scullc3771072019-09-19 13:30:42 +0100166 panic("Unable to update boot flow.");
Andrew Scullb2910562019-09-17 14:08:27 +0100167 }
168
169 mm_defrag(mm_stage1_locked, &ppool);
170 mm_unlock_stage1(&mm_stage1_locked);
171
172 /* Initialise the API page pool. ppool will be empty from now on. */
173 api_init(&ppool);
174
175 /* Enable TLB invalidation for VM page table updates. */
176 mm_vm_enable_invalidation();
177
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100178 if (manifest.ffa_tee_enabled) {
Andrew Walbran41a49d82020-01-10 17:46:38 +0000179 /* Set up message buffers for TEE dispatcher. */
180 arch_tee_init();
181 }
182
Andrew Walbran17eebf92020-02-05 16:35:49 +0000183 dlog_info("Hafnium initialisation completed\n");
Andrew Scullb2910562019-09-17 14:08:27 +0100184}