blob: b536e04a6e7e719d6bb2dc52a4efbaa359153492 [file] [log] [blame]
Andrew Scullb2910562019-09-17 14:08:27 +01001/*
2 * Copyright 2018 The Hafnium Authors.
3 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scullb2910562019-09-17 14:08:27 +01007 */
8
9#include "hf/arch/init.h"
10
11#include <stdalign.h>
12#include <stddef.h>
13
Olivier Deprez112d2b52020-09-30 07:39:23 +020014#include "hf/arch/other_world.h"
Olivier Deprez55a189e2021-06-09 15:45:27 +020015#include "hf/arch/plat/ffa.h"
Andrew Walbran41a49d82020-01-10 17:46:38 +000016
Andrew Scullb2910562019-09-17 14:08:27 +010017#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"
Andrew Scull3c257452019-11-26 13:32:50 +000023#include "hf/fdt_handler.h"
Andrew Scullb2910562019-09-17 14:08:27 +010024#include "hf/load.h"
J-Alves77b6f4f2023-03-15 11:34:49 +000025#include "hf/manifest.h"
Andrew Scullb2910562019-09-17 14:08:27 +010026#include "hf/mm.h"
27#include "hf/mpool.h"
28#include "hf/panic.h"
Andrew Scull3c257452019-11-26 13:32:50 +000029#include "hf/plat/boot_flow.h"
Andrew Scullb2910562019-09-17 14:08:27 +010030#include "hf/plat/console.h"
Madhukar Pappireddy72454a12021-08-03 12:21:46 -050031#include "hf/plat/interrupts.h"
Andrew Scull3c257452019-11-26 13:32:50 +000032#include "hf/plat/iommu.h"
Andrew Scullb2910562019-09-17 14:08:27 +010033#include "hf/std.h"
34#include "hf/vm.h"
35
36#include "vmapi/hf/call.h"
37
Andrew Walbran5de9c3d2020-02-10 13:35:29 +000038alignas(MM_PPOOL_ENTRY_SIZE) char ptable_buf[MM_PPOOL_ENTRY_SIZE * HEAP_PAGES];
Andrew Scullb2910562019-09-17 14:08:27 +010039
40static struct mpool ppool;
41
42/**
43 * Performs one-time initialisation of memory management for the hypervisor.
44 *
45 * This is the only C code entry point called with MMU and caching disabled. The
46 * page table returned is used to set up the MMU and caches for all subsequent
47 * code.
48 */
49void one_time_init_mm(void)
50{
51 /* Make sure the console is initialised before calling dlog. */
52 plat_console_init();
53
Olivier Deprez55a189e2021-06-09 15:45:27 +020054 plat_ffa_log_init();
Andrew Scullb2910562019-09-17 14:08:27 +010055
Andrew Walbran5de9c3d2020-02-10 13:35:29 +000056 mpool_init(&ppool, MM_PPOOL_ENTRY_SIZE);
Andrew Scullb2910562019-09-17 14:08:27 +010057 mpool_add_chunk(&ppool, ptable_buf, sizeof(ptable_buf));
58
59 if (!mm_init(&ppool)) {
60 panic("mm_init failed");
61 }
62}
63
64/**
65 * Performs one-time initialisation of the hypervisor.
66 */
67void one_time_init(void)
68{
David Brazdila2358d42020-01-27 18:51:38 +000069 struct string manifest_fname = STRING_INIT("manifest.dtb");
David Brazdilb856be62020-03-25 10:14:55 +000070 struct fdt fdt;
David Brazdila2358d42020-01-27 18:51:38 +000071 enum manifest_return_code manifest_ret;
J-Alvesdf099be2024-05-13 12:47:33 +010072 struct boot_params *params;
Andrew Scullb2910562019-09-17 14:08:27 +010073 struct boot_params_update update;
Andrew Scullb2910562019-09-17 14:08:27 +010074 struct memiter cpio;
David Brazdila2358d42020-01-27 18:51:38 +000075 struct memiter manifest_it;
Andrew Scullb2910562019-09-17 14:08:27 +010076 void *initrd;
77 size_t i;
78 struct mm_stage1_locked mm_stage1_locked;
Olivier Deprez93644652022-09-09 11:01:12 +020079 struct manifest *manifest;
Andrew Scullb2910562019-09-17 14:08:27 +010080
81 arch_one_time_init();
82
83 /* Enable locks now that mm is initialised. */
84 dlog_enable_lock();
85 mpool_enable_locks();
86
87 mm_stage1_locked = mm_lock_stage1();
88
David Brazdilb856be62020-03-25 10:14:55 +000089 if (!fdt_map(&fdt, mm_stage1_locked, plat_boot_flow_get_fdt_addr(),
90 &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +000091 panic("Unable to map FDT.");
Andrew Scull3c257452019-11-26 13:32:50 +000092 }
93
J-Alvesdf099be2024-05-13 12:47:33 +010094 static_assert(sizeof(struct boot_params) <= MM_PPOOL_ENTRY_SIZE,
95 "The sizeof boot params must fit an entry of the mpool.");
96 params = (struct boot_params *)mpool_alloc(&ppool);
97
98 if (params == NULL) {
99 panic("Could not use memory pool to allocate boot params.");
100 }
101
102 if (!boot_flow_get_params(params, &fdt)) {
David Brazdila2358d42020-01-27 18:51:38 +0000103 panic("Could not parse boot params.");
Andrew Scullb2910562019-09-17 14:08:27 +0100104 }
105
J-Alvesdf099be2024-05-13 12:47:33 +0100106 for (i = 0; i < params->mem_ranges_count; ++i) {
Karl Meakine8937d92024-03-19 16:04:25 +0000107 dlog_info("Memory range: %#lx - %#lx\n",
J-Alvesdf099be2024-05-13 12:47:33 +0100108 pa_addr(params->mem_ranges[i].begin),
109 pa_addr(params->mem_ranges[i].end) - 1);
Andrew Scullb2910562019-09-17 14:08:27 +0100110 }
111
Olivier Deprez62d99e32020-01-09 15:58:07 +0100112 /*
113 * Hafnium manifest is either gathered from the ramdisk or passed
114 * directly to Hafnium entry point by the earlier bootloader stage.
115 * If the ramdisk start address is non-zero it hints the manifest
116 * shall be looked up from the ramdisk. If zero, assume the address
117 * passed to Hafnium entry point is the manifest address.
118 */
J-Alvesdf099be2024-05-13 12:47:33 +0100119 if (pa_addr(params->initrd_begin)) {
Karl Meakine8937d92024-03-19 16:04:25 +0000120 dlog_info("Ramdisk range: %#lx - %#lx\n",
J-Alvesdf099be2024-05-13 12:47:33 +0100121 pa_addr(params->initrd_begin),
122 pa_addr(params->initrd_end) - 1);
Andrew Scullb2910562019-09-17 14:08:27 +0100123
Olivier Deprez62d99e32020-01-09 15:58:07 +0100124 /* Map initrd in, and initialise cpio parser. */
J-Alvesdf099be2024-05-13 12:47:33 +0100125 initrd = mm_identity_map(mm_stage1_locked, params->initrd_begin,
126 params->initrd_end, MM_MODE_R, &ppool);
Olivier Deprez62d99e32020-01-09 15:58:07 +0100127 if (!initrd) {
128 panic("Unable to map initrd.");
129 }
130
J-Alvesdf099be2024-05-13 12:47:33 +0100131 memiter_init(&cpio, initrd,
132 pa_difference(params->initrd_begin,
133 params->initrd_end));
Olivier Deprez62d99e32020-01-09 15:58:07 +0100134
135 if (!cpio_get_file(&cpio, &manifest_fname, &manifest_it)) {
136 panic("Could not find manifest in initrd.");
137 }
138 } else {
139 manifest_it = fdt.buf;
Andrew Scullb2910562019-09-17 14:08:27 +0100140 }
141
Karl Meakine8937d92024-03-19 16:04:25 +0000142 dlog_verbose("Manifest range: %p - %p (%ld bytes)\n",
143 (void *)manifest_it.next, (void *)manifest_it.limit,
144 manifest_it.limit - manifest_it.next);
Dmitrii Martynov89190c92023-02-23 20:20:10 +0300145 if (!is_aligned(manifest_it.next, 4)) {
146 panic("Manifest not aligned.");
147 }
148
Olivier Deprez62d99e32020-01-09 15:58:07 +0100149 manifest_ret = manifest_init(mm_stage1_locked, &manifest, &manifest_it,
J-Alvesdf099be2024-05-13 12:47:33 +0100150 params, &ppool);
Andrew Scullb2910562019-09-17 14:08:27 +0100151
David Brazdila2358d42020-01-27 18:51:38 +0000152 if (manifest_ret != MANIFEST_SUCCESS) {
153 panic("Could not parse manifest: %s.",
154 manifest_strerror(manifest_ret));
155 }
156
Olivier Deprez93644652022-09-09 11:01:12 +0200157 plat_ffa_set_tee_enabled(manifest->ffa_tee_enabled);
J-Alvesa09ac2d2022-06-07 13:46:59 +0100158
David Brazdilb856be62020-03-25 10:14:55 +0000159 if (!plat_iommu_init(&fdt, mm_stage1_locked, &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +0000160 panic("Could not initialize IOMMUs.");
161 }
162
David Brazdilb856be62020-03-25 10:14:55 +0000163 if (!fdt_unmap(&fdt, mm_stage1_locked, &ppool)) {
David Brazdila2358d42020-01-27 18:51:38 +0000164 panic("Unable to unmap FDT.");
165 }
166
J-Alvesdf099be2024-05-13 12:47:33 +0100167 cpu_module_init(params->cpu_ids, params->cpu_count);
David Brazdila2358d42020-01-27 18:51:38 +0000168
Madhukar Pappireddy72454a12021-08-03 12:21:46 -0500169 if (!plat_interrupts_controller_driver_init(&fdt, mm_stage1_locked,
170 &ppool)) {
171 panic("Could not initialize Interrupt Controller driver.");
172 }
173
Andrew Scullb2910562019-09-17 14:08:27 +0100174 /* Load all VMs. */
Andrew Scullb2910562019-09-17 14:08:27 +0100175 update.reserved_ranges_count = 0;
J-Alvesdf099be2024-05-13 12:47:33 +0100176 if (!load_vms(mm_stage1_locked, manifest, &cpio, params, &update,
Andrew Scull72b43c02019-09-18 13:53:45 +0100177 &ppool)) {
178 panic("Unable to load VMs.");
Andrew Scullb2910562019-09-17 14:08:27 +0100179 }
180
Olivier Deprez93644652022-09-09 11:01:12 +0200181 if (!boot_flow_update(mm_stage1_locked, manifest, &update, &cpio,
David Brazdile6f83222019-09-23 14:47:37 +0100182 &ppool)) {
Andrew Scullc3771072019-09-19 13:30:42 +0100183 panic("Unable to update boot flow.");
Andrew Scullb2910562019-09-17 14:08:27 +0100184 }
185
J-Alvesdf099be2024-05-13 12:47:33 +0100186 /* Free space allocated for the boot parameters. */
187 mpool_free(&ppool, params);
188
Olivier Deprez93644652022-09-09 11:01:12 +0200189 /* Now manifest parsing has completed free the resourses used. */
190 manifest_deinit(&ppool);
191
Andrew Scullb2910562019-09-17 14:08:27 +0100192 mm_unlock_stage1(&mm_stage1_locked);
193
Andrew Scullb2910562019-09-17 14:08:27 +0100194 /* Enable TLB invalidation for VM page table updates. */
195 mm_vm_enable_invalidation();
196
Daniel Boulbybaeaf2e2021-12-09 11:42:36 +0000197 /* Perform platform specfic FF-A initialization. */
Raghu Krishnamurthyf5fec202022-09-30 07:25:10 -0700198 plat_ffa_init(&ppool);
199
200 /* Initialise the API page pool. ppool will be empty from now on. */
201 api_init(&ppool);
Andrew Walbran41a49d82020-01-10 17:46:38 +0000202
Andrew Walbran17eebf92020-02-05 16:35:49 +0000203 dlog_info("Hafnium initialisation completed\n");
Andrew Scullb2910562019-09-17 14:08:27 +0100204}