blob: 9aa1ccd27ffb68bbd15c4697164bb61f4ceb7cae [file] [log] [blame]
J-Alves6e0abc42024-12-30 16:51:16 +00001/*
2 * Copyright 2024 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/partition_pkg.h"
10
11#include <stdint.h>
12
13#include "hf/arch/std.h"
14
15#include "hf/addr.h"
16#include "hf/check.h"
17#include "hf/dlog.h"
18#include "hf/mm.h"
19#include "hf/sp_pkg.h"
20#include "hf/std.h"
21#include "hf/transfer_list.h"
22
23static void dump_partition_package(struct partition_pkg *pkg)
24{
25 dlog_verbose("%s: total %lx %lx\n", __func__, pa_addr(pkg->total.begin),
26 pa_addr(pkg->total.end));
27 dlog_verbose("%s: pm: %lx %lx\n", __func__, pa_addr(pkg->pm.begin),
28 pa_addr(pkg->pm.end));
29 dlog_verbose("%s: img: %lx %lx\n", __func__, pa_addr(pkg->img.begin),
30 pa_addr(pkg->img.end));
31 dlog_verbose("%s: boot_info: %lx %lx\n", __func__,
32 pa_addr(pkg->boot_info.begin),
33 pa_addr(pkg->boot_info.end));
34 if (mem_range_is_valid(pkg->hob)) {
35 dlog_verbose("%s: hob %lx %lx\n", __func__,
36 pa_addr(pkg->hob.begin), pa_addr(pkg->hob.end));
37 }
38}
39
40static bool partition_pkg_from_sp_pkg(struct mm_stage1_locked stage1_locked,
41 paddr_t pkg_start,
42 struct partition_pkg *pkg,
43 struct mpool *ppool)
44{
45 struct sp_pkg_header header;
46 bool ret = sp_pkg_init(stage1_locked, pkg_start, &header, ppool);
47 size_t total_mem_size = sp_pkg_get_mem_size(&header);
48
49 pkg->total.begin = pkg_start;
50 pkg->total.end = pa_add(pkg_start, total_mem_size);
51
52 pkg->pm.begin = pa_add(pkg_start, header.pm_offset);
53 pkg->pm.end = pa_add(pkg->pm.begin, header.pm_size);
54
55 pkg->img.begin = pa_add(pkg_start, header.img_offset);
56 pkg->img.end = pa_add(pkg->img.begin, header.img_size);
57
58 /*
59 * Repurpose the first page of the SP Package.
60 * FF-A boot info will overwrite the package, but it doesn't
61 * matter at this stage, given Hafnium already parsed it.
62 */
63 pkg->boot_info.begin = pkg_start;
64 pkg->boot_info.end = pa_add(pkg_start, header.pm_offset);
65
66 /* HOB section doesn't exist in the SP Pkg type. */
67 pkg->hob.begin = pa_init(0);
68 pkg->hob.end = pa_init(0);
69
70 dump_partition_package(pkg);
71
72 /* Map the whole package as RO. */
73 CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
74 MM_MODE_R, ppool) != NULL);
75
76 return ret;
77}
78
J-Alves01337a32024-11-18 17:51:59 +000079/**
80 * It creates a memory range structure which relates to the region of the
81 * TE data.
82 * It returns false if there is no TE entry with the specified type.
83 * It returns true, if there is a TE entry with the specified type, and
84 * returns the memory range via `mem_range`.
85 */
86static bool partition_pkg_init_memory_range_from_te(
87 struct mem_range *mem_range, struct transfer_list_entry *te)
88{
89 void *te_data;
90
91 assert(mem_range != NULL);
92
93 te_data = transfer_list_entry_data(te);
94
95 if (te == NULL || te_data == NULL) {
96 mem_range->begin = pa_init(0);
97 mem_range->end = pa_init(0);
98 return false;
99 }
100
101 mem_range->begin = pa_from_va(va_init((uintptr_t)te_data));
102 mem_range->end = pa_add(mem_range->begin, te->data_size);
103
104 return true;
105}
106
107static bool partition_pkg_from_tl(struct mm_stage1_locked stage1_locked,
108 paddr_t pkg_start, struct partition_pkg *pkg,
109 struct mpool *ppool)
110{
111 struct transfer_list_header *tl = ptr_from_va(va_from_pa(pkg_start));
112 enum transfer_list_ops tl_res;
113
114 dlog_verbose("%s: partition loaded in a transfer list.\n", __func__);
115
116 /* The total memory for the partition package. */
117 pkg->total.begin = pkg_start;
118 pkg->total.end = pa_add(pkg_start, tl->size);
119
120 /* Map the whole TL as RO. */
121 CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
122 MM_MODE_R, ppool));
123
124 tl_res = transfer_list_check_header(tl);
125
126 if (tl_res == TL_OPS_NON || tl_res == TL_OPS_CUS) {
127 return false;
128 }
129
130 /*
131 * Get the memory ranges from the TL for:
132 * - FFA_MANIFEST.
133 * - Partition Image.
134 */
135 if (!partition_pkg_init_memory_range_from_te(
136 &(pkg->pm),
137 transfer_list_find(tl, TL_TAG_DT_FFA_MANIFEST)) ||
138 !partition_pkg_init_memory_range_from_te(
139 &(pkg->img),
140 transfer_list_find(tl, TL_TAG_FFA_SP_BINARY))) {
141 return false;
142 }
143
144 /* An HOB entry is optional. */
145 partition_pkg_init_memory_range_from_te(
146 &(pkg->hob), transfer_list_find(tl, TL_TAG_HOB_LIST));
147
148 if (!mem_range_aligns(pkg->pm, PAGE_SIZE)) {
149 dlog_error(
150 "%s: the partition manifest range must be 4k page "
151 "aligned.\n",
152 __func__);
153 return false;
154 }
155
156 if (!mem_range_aligns(pkg->img, PAGE_SIZE)) {
157 dlog_error(
158 "%s: the partition image range must be 4k page "
159 "aligned.\n",
160 __func__);
161 return false;
162 }
163
164 if (mem_range_is_valid(pkg->hob) &&
165 !mem_range_aligns(pkg->hob, PAGE_SIZE)) {
166 dlog_error("%s: the hob range must be 4k page aligned.\n",
167 __func__);
168 return false;
169 }
170
171 /*
172 * For the boot information descriptor, repurpose the TL's first page.
173 * The TL is only processed by Hafnium, and all items are placed at
174 * a page aligned offset.
175 * At this point, all references to artefacts in the TL have been
176 * obtained so the first page of the package can be repurposed to the
177 * FF-A boot information. There is no expectation that the boot info
178 * descriptors will need more than a page for the time being. If it does
179 * get full, Hafnium will fail at populating the boot info descriptors.
180 */
181 pkg->boot_info.begin = pkg_start;
182 pkg->boot_info.end = pa_add(pkg_start, PAGE_SIZE);
183
184 dump_partition_package(pkg);
185
186 return true;
187}
188
J-Alves6e0abc42024-12-30 16:51:16 +0000189bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
190 paddr_t pkg_start, struct partition_pkg *pkg,
191 struct mpool *ppool)
192{
193 bool ret = false;
194 paddr_t pkg_first_page = pa_add(pkg_start, PAGE_SIZE);
195 uint32_t *magic;
196 void *mapped_ptr;
197
198 /* Firstly, map a single page to be able to read package header. */
199 mapped_ptr = mm_identity_map(stage1_locked, pkg_start, pkg_first_page,
200 MM_MODE_R, ppool);
201 assert(mapped_ptr != NULL);
202 assert(pkg != NULL);
203
204 magic = (uint32_t *)mapped_ptr;
205
206 switch (*magic) {
207 case SP_PKG_HEADER_MAGIC:
208 /*
209 * Leave memory mapped in case it succeeded, to be cleared
210 * later.
211 */
212 if (!partition_pkg_from_sp_pkg(stage1_locked, pkg_start, pkg,
213 ppool)) {
214 goto out;
215 }
216 break;
J-Alves01337a32024-11-18 17:51:59 +0000217 case TRANSFER_LIST_SIGNATURE:
218 if (!partition_pkg_from_tl(stage1_locked, pkg_start, pkg,
219 ppool)) {
220 goto out;
221 }
222 break;
J-Alves6e0abc42024-12-30 16:51:16 +0000223 default:
224 dlog_error("%s: invalid secure partition package %x @ %lx\n",
225 __func__, *magic, (uint64_t)magic);
226 goto out;
227 }
228
229 dump_partition_package(pkg);
230
231 /**
232 * The total memory range should encompass the remaining.
233 * Assert that none of the memory ranges are out of bounds.
234 */
235 assert(mem_range_contains_range(pkg->total, pkg->img));
236 assert(mem_range_contains_range(pkg->total, pkg->pm));
237 assert(mem_range_contains_range(pkg->total, pkg->boot_info));
238 assert(!mem_range_is_valid(pkg->hob) ||
239 mem_range_contains_range(pkg->total, pkg->hob));
240
241 /* Map Boot info section as RW. */
242 if (pa_addr(pkg->boot_info.begin) != 0U &&
243 pa_addr(pkg->boot_info.end) != 0U) {
244 CHECK(mm_identity_map(stage1_locked, pkg->boot_info.begin,
245 pkg->boot_info.end, MM_MODE_R | MM_MODE_W,
246 ppool) != NULL);
247 }
248
249 ret = true;
250
251out:
252 /* If failing unmap the memory. */
253 if (!ret) {
254 CHECK(mm_unmap(stage1_locked, pkg_start, pkg_first_page,
255 ppool));
256 }
257
258 return ret;
259}
260
261void partition_pkg_deinit(struct mm_stage1_locked stage1_locked,
262 struct partition_pkg *pkg, struct mpool *ppool)
263{
264 CHECK(mm_unmap(stage1_locked, pkg->total.begin, pkg->total.end, ppool));
265}