feat(tl): package SPs in TL
In addition to the SP Pkg, allow for SPs to be loaded
as Transfer Lists.
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: Ic0297aae7b543c8ba91bbb866efae60db82de377
diff --git a/src/partition_pkg.c b/src/partition_pkg.c
index 093de43..9aa1ccd 100644
--- a/src/partition_pkg.c
+++ b/src/partition_pkg.c
@@ -76,6 +76,116 @@
return ret;
}
+/**
+ * It creates a memory range structure which relates to the region of the
+ * TE data.
+ * It returns false if there is no TE entry with the specified type.
+ * It returns true, if there is a TE entry with the specified type, and
+ * returns the memory range via `mem_range`.
+ */
+static bool partition_pkg_init_memory_range_from_te(
+ struct mem_range *mem_range, struct transfer_list_entry *te)
+{
+ void *te_data;
+
+ assert(mem_range != NULL);
+
+ te_data = transfer_list_entry_data(te);
+
+ if (te == NULL || te_data == NULL) {
+ mem_range->begin = pa_init(0);
+ mem_range->end = pa_init(0);
+ return false;
+ }
+
+ mem_range->begin = pa_from_va(va_init((uintptr_t)te_data));
+ mem_range->end = pa_add(mem_range->begin, te->data_size);
+
+ return true;
+}
+
+static bool partition_pkg_from_tl(struct mm_stage1_locked stage1_locked,
+ paddr_t pkg_start, struct partition_pkg *pkg,
+ struct mpool *ppool)
+{
+ struct transfer_list_header *tl = ptr_from_va(va_from_pa(pkg_start));
+ enum transfer_list_ops tl_res;
+
+ dlog_verbose("%s: partition loaded in a transfer list.\n", __func__);
+
+ /* The total memory for the partition package. */
+ pkg->total.begin = pkg_start;
+ pkg->total.end = pa_add(pkg_start, tl->size);
+
+ /* Map the whole TL as RO. */
+ CHECK(mm_identity_map(stage1_locked, pkg->total.begin, pkg->total.end,
+ MM_MODE_R, ppool));
+
+ tl_res = transfer_list_check_header(tl);
+
+ if (tl_res == TL_OPS_NON || tl_res == TL_OPS_CUS) {
+ return false;
+ }
+
+ /*
+ * Get the memory ranges from the TL for:
+ * - FFA_MANIFEST.
+ * - Partition Image.
+ */
+ if (!partition_pkg_init_memory_range_from_te(
+ &(pkg->pm),
+ transfer_list_find(tl, TL_TAG_DT_FFA_MANIFEST)) ||
+ !partition_pkg_init_memory_range_from_te(
+ &(pkg->img),
+ transfer_list_find(tl, TL_TAG_FFA_SP_BINARY))) {
+ return false;
+ }
+
+ /* An HOB entry is optional. */
+ partition_pkg_init_memory_range_from_te(
+ &(pkg->hob), transfer_list_find(tl, TL_TAG_HOB_LIST));
+
+ if (!mem_range_aligns(pkg->pm, PAGE_SIZE)) {
+ dlog_error(
+ "%s: the partition manifest range must be 4k page "
+ "aligned.\n",
+ __func__);
+ return false;
+ }
+
+ if (!mem_range_aligns(pkg->img, PAGE_SIZE)) {
+ dlog_error(
+ "%s: the partition image range must be 4k page "
+ "aligned.\n",
+ __func__);
+ return false;
+ }
+
+ if (mem_range_is_valid(pkg->hob) &&
+ !mem_range_aligns(pkg->hob, PAGE_SIZE)) {
+ dlog_error("%s: the hob range must be 4k page aligned.\n",
+ __func__);
+ return false;
+ }
+
+ /*
+ * For the boot information descriptor, repurpose the TL's first page.
+ * The TL is only processed by Hafnium, and all items are placed at
+ * a page aligned offset.
+ * At this point, all references to artefacts in the TL have been
+ * obtained so the first page of the package can be repurposed to the
+ * FF-A boot information. There is no expectation that the boot info
+ * descriptors will need more than a page for the time being. If it does
+ * get full, Hafnium will fail at populating the boot info descriptors.
+ */
+ pkg->boot_info.begin = pkg_start;
+ pkg->boot_info.end = pa_add(pkg_start, PAGE_SIZE);
+
+ dump_partition_package(pkg);
+
+ return true;
+}
+
bool partition_pkg_init(struct mm_stage1_locked stage1_locked,
paddr_t pkg_start, struct partition_pkg *pkg,
struct mpool *ppool)
@@ -104,6 +214,12 @@
goto out;
}
break;
+ case TRANSFER_LIST_SIGNATURE:
+ if (!partition_pkg_from_tl(stage1_locked, pkg_start, pkg,
+ ppool)) {
+ goto out;
+ }
+ break;
default:
dlog_error("%s: invalid secure partition package %x @ %lx\n",
__func__, *magic, (uint64_t)magic);