blob: 4fb476b6bbff46c2d6c94ecc9609dadb6e140e63 [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
Kathleen Capellaf38bfff2024-10-16 18:12:59 -040070 if (ret) {
71 /* Map the whole package as RO. */
72 CHECK(mm_identity_map(stage1_locked, pkg->total.begin,
73 pkg->total.end, MM_MODE_R,
74 ppool) != NULL);
75 }
J-Alves6e0abc42024-12-30 16:51:16 +000076
77 return ret;
78}
79
J-Alves01337a32024-11-18 17:51:59 +000080/**
81 * It creates a memory range structure which relates to the region of the
82 * TE data.
83 * It returns false if there is no TE entry with the specified type.
84 * It returns true, if there is a TE entry with the specified type, and
85 * returns the memory range via `mem_range`.
86 */
87static bool partition_pkg_init_memory_range_from_te(
88 struct mem_range *mem_range, struct transfer_list_entry *te)
89{
90 void *te_data;
91
92 assert(mem_range != NULL);
93
94 te_data = transfer_list_entry_data(te);
95
96 if (te == NULL || te_data == NULL) {
97 mem_range->begin = pa_init(0);
98 mem_range->end = pa_init(0);
99 return false;
100 }
101
102 mem_range->begin = pa_from_va(va_init((uintptr_t)te_data));
103 mem_range->end = pa_add(mem_range->begin, te->data_size);
104
105 return true;
106}
107
108static bool partition_pkg_from_tl(struct mm_stage1_locked stage1_locked,
109 paddr_t pkg_start, struct partition_pkg *pkg,
110 struct mpool *ppool)
111{
112 struct transfer_list_header *tl = ptr_from_va(va_from_pa(pkg_start));
113 enum transfer_list_ops tl_res;
114
115 dlog_verbose("%s: partition loaded in a transfer list.\n", __func__);
116
117 /* The total memory for the partition package. */
118 pkg->total.begin = pkg_start;
119 pkg->total.end = pa_add(pkg_start, tl->size);
120
121 /* Map the whole TL as RO. */
122 CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
123 MM_MODE_R, ppool));
124
125 tl_res = transfer_list_check_header(tl);
126
127 if (tl_res == TL_OPS_NON || tl_res == TL_OPS_CUS) {
128 return false;
129 }
130
131 /*
132 * Get the memory ranges from the TL for:
133 * - FFA_MANIFEST.
134 * - Partition Image.
135 */
136 if (!partition_pkg_init_memory_range_from_te(
137 &(pkg->pm),
138 transfer_list_find(tl, TL_TAG_DT_FFA_MANIFEST)) ||
139 !partition_pkg_init_memory_range_from_te(
140 &(pkg->img),
141 transfer_list_find(tl, TL_TAG_FFA_SP_BINARY))) {
142 return false;
143 }
144
145 /* An HOB entry is optional. */
146 partition_pkg_init_memory_range_from_te(
147 &(pkg->hob), transfer_list_find(tl, TL_TAG_HOB_LIST));
148
149 if (!mem_range_aligns(pkg->pm, PAGE_SIZE)) {
150 dlog_error(
151 "%s: the partition manifest range must be 4k page "
152 "aligned.\n",
153 __func__);
154 return false;
155 }
156
157 if (!mem_range_aligns(pkg->img, PAGE_SIZE)) {
158 dlog_error(
159 "%s: the partition image range must be 4k page "
160 "aligned.\n",
161 __func__);
162 return false;
163 }
164
165 if (mem_range_is_valid(pkg->hob) &&
166 !mem_range_aligns(pkg->hob, PAGE_SIZE)) {
167 dlog_error("%s: the hob range must be 4k page aligned.\n",
168 __func__);
169 return false;
170 }
171
172 /*
173 * For the boot information descriptor, repurpose the TL's first page.
174 * The TL is only processed by Hafnium, and all items are placed at
175 * a page aligned offset.
176 * At this point, all references to artefacts in the TL have been
177 * obtained so the first page of the package can be repurposed to the
178 * FF-A boot information. There is no expectation that the boot info
179 * descriptors will need more than a page for the time being. If it does
180 * get full, Hafnium will fail at populating the boot info descriptors.
181 */
182 pkg->boot_info.begin = pkg_start;
183 pkg->boot_info.end = pa_add(pkg_start, PAGE_SIZE);
184
J-Alves01337a32024-11-18 17:51:59 +0000185 return true;
186}
187
J-Alves6e0abc42024-12-30 16:51:16 +0000188bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
189 paddr_t pkg_start, struct partition_pkg *pkg,
190 struct mpool *ppool)
191{
192 bool ret = false;
193 paddr_t pkg_first_page = pa_add(pkg_start, PAGE_SIZE);
194 uint32_t *magic;
195 void *mapped_ptr;
196
197 /* Firstly, map a single page to be able to read package header. */
198 mapped_ptr = mm_identity_map(stage1_locked, pkg_start, pkg_first_page,
199 MM_MODE_R, ppool);
200 assert(mapped_ptr != NULL);
201 assert(pkg != NULL);
202
203 magic = (uint32_t *)mapped_ptr;
204
205 switch (*magic) {
206 case SP_PKG_HEADER_MAGIC:
207 /*
208 * Leave memory mapped in case it succeeded, to be cleared
209 * later.
210 */
211 if (!partition_pkg_from_sp_pkg(stage1_locked, pkg_start, pkg,
212 ppool)) {
213 goto out;
214 }
215 break;
J-Alves01337a32024-11-18 17:51:59 +0000216 case TRANSFER_LIST_SIGNATURE:
217 if (!partition_pkg_from_tl(stage1_locked, pkg_start, pkg,
218 ppool)) {
219 goto out;
220 }
221 break;
J-Alves6e0abc42024-12-30 16:51:16 +0000222 default:
223 dlog_error("%s: invalid secure partition package %x @ %lx\n",
224 __func__, *magic, (uint64_t)magic);
225 goto out;
226 }
227
228 dump_partition_package(pkg);
229
230 /**
231 * The total memory range should encompass the remaining.
232 * Assert that none of the memory ranges are out of bounds.
233 */
234 assert(mem_range_contains_range(pkg->total, pkg->img));
235 assert(mem_range_contains_range(pkg->total, pkg->pm));
236 assert(mem_range_contains_range(pkg->total, pkg->boot_info));
237 assert(!mem_range_is_valid(pkg->hob) ||
238 mem_range_contains_range(pkg->total, pkg->hob));
239
240 /* Map Boot info section as RW. */
241 if (pa_addr(pkg->boot_info.begin) != 0U &&
242 pa_addr(pkg->boot_info.end) != 0U) {
243 CHECK(mm_identity_map(stage1_locked, pkg->boot_info.begin,
244 pkg->boot_info.end, MM_MODE_R | MM_MODE_W,
245 ppool) != NULL);
246 }
247
248 ret = true;
249
250out:
251 /* If failing unmap the memory. */
252 if (!ret) {
253 CHECK(mm_unmap(stage1_locked, pkg_start, pkg_first_page,
254 ppool));
255 }
256
257 return ret;
258}
259
260void partition_pkg_deinit(struct mm_stage1_locked stage1_locked,
261 struct partition_pkg *pkg, struct mpool *ppool)
262{
263 CHECK(mm_unmap(stage1_locked, pkg->total.begin, pkg->total.end, ppool));
264}