10cb64d01SAchin Gupta /*
28c829a92SManish V Badarkhe * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
30cb64d01SAchin Gupta *
40cb64d01SAchin Gupta * SPDX-License-Identifier: BSD-3-Clause
50cb64d01SAchin Gupta */
60cb64d01SAchin Gupta
70cb64d01SAchin Gupta #include <assert.h>
852696946SOlivier Deprez #include <errno.h>
94ce3e99aSScott Branden #include <inttypes.h>
100cb64d01SAchin Gupta #include <libfdt.h>
114ce3e99aSScott Branden #include <stdint.h>
124ce3e99aSScott Branden #include <string.h>
130cb64d01SAchin Gupta
14cb7b9db1SVarun Wadekar #include <common/bl_common.h>
150cb64d01SAchin Gupta #include <common/debug.h>
160cb64d01SAchin Gupta #include <common/fdt_wrappers.h>
1723d5ba86SOlivier Deprez #include <lib/xlat_tables/xlat_tables_v2.h>
180cb64d01SAchin Gupta #include <platform_def.h>
190cb64d01SAchin Gupta #include <services/spm_core_manifest.h>
200cb64d01SAchin Gupta
2152696946SOlivier Deprez #define ATTRIBUTE_ROOT_NODE_STR "attribute"
2252696946SOlivier Deprez
230cb64d01SAchin Gupta /*******************************************************************************
2452696946SOlivier Deprez * SPMC attribute node parser
250cb64d01SAchin Gupta ******************************************************************************/
manifest_parse_attribute(spmc_manifest_attribute_t * attr,const void * fdt,int node)2652696946SOlivier Deprez static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
270cb64d01SAchin Gupta const void *fdt,
280cb64d01SAchin Gupta int node)
290cb64d01SAchin Gupta {
30ff4e6c35SAndre Przywara uint32_t val32;
3152696946SOlivier Deprez int rc;
320cb64d01SAchin Gupta
3352696946SOlivier Deprez assert((attr != NULL) && (fdt != NULL));
340cb64d01SAchin Gupta
35ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
3652696946SOlivier Deprez if (rc != 0) {
37662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n",
3852696946SOlivier Deprez "major");
3952696946SOlivier Deprez return rc;
400cb64d01SAchin Gupta }
410cb64d01SAchin Gupta
42ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
4352696946SOlivier Deprez if (rc != 0) {
44662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n",
4552696946SOlivier Deprez "minor");
4652696946SOlivier Deprez return rc;
470cb64d01SAchin Gupta }
480cb64d01SAchin Gupta
49ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
5052696946SOlivier Deprez if (rc != 0) {
51ac03ac5eSMax Shvetsov ERROR("Missing SPMC ID in manifest.\n");
5252696946SOlivier Deprez return rc;
53ac03ac5eSMax Shvetsov }
5452696946SOlivier Deprez
5552696946SOlivier Deprez attr->spmc_id = val32 & 0xffff;
56ac03ac5eSMax Shvetsov
57ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
5852696946SOlivier Deprez if (rc != 0) {
5952696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n",
6052696946SOlivier Deprez "Execution state");
6152696946SOlivier Deprez }
620cb64d01SAchin Gupta
63ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
6452696946SOlivier Deprez if (rc != 0) {
6552696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n",
6652696946SOlivier Deprez "Binary size");
6752696946SOlivier Deprez }
680cb64d01SAchin Gupta
69ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
7052696946SOlivier Deprez if (rc != 0) {
7152696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n",
7252696946SOlivier Deprez "Load address");
7352696946SOlivier Deprez }
740cb64d01SAchin Gupta
75ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
7652696946SOlivier Deprez if (rc != 0) {
7752696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n",
7852696946SOlivier Deprez "Entry point");
7952696946SOlivier Deprez }
800cb64d01SAchin Gupta
8152696946SOlivier Deprez VERBOSE("SPM Core manifest attribute section:\n");
8252696946SOlivier Deprez VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version);
8352696946SOlivier Deprez VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id);
840cb64d01SAchin Gupta VERBOSE(" binary_size: 0x%x\n", attr->binary_size);
854ce3e99aSScott Branden VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address);
864ce3e99aSScott Branden VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint);
870cb64d01SAchin Gupta
880cb64d01SAchin Gupta return 0;
890cb64d01SAchin Gupta }
900cb64d01SAchin Gupta
910cb64d01SAchin Gupta /*******************************************************************************
920cb64d01SAchin Gupta * Root node handler
930cb64d01SAchin Gupta ******************************************************************************/
manifest_parse_root(spmc_manifest_attribute_t * manifest,const void * fdt,int root)9452696946SOlivier Deprez static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
950cb64d01SAchin Gupta const void *fdt,
960cb64d01SAchin Gupta int root)
970cb64d01SAchin Gupta {
980cb64d01SAchin Gupta int node;
990cb64d01SAchin Gupta
10052696946SOlivier Deprez assert(manifest != NULL);
10152696946SOlivier Deprez
10252696946SOlivier Deprez node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
10352696946SOlivier Deprez sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
1040cb64d01SAchin Gupta if (node < 0) {
10552696946SOlivier Deprez ERROR("Root node doesn't contain subnode '%s'\n",
10652696946SOlivier Deprez ATTRIBUTE_ROOT_NODE_STR);
10752696946SOlivier Deprez return node;
1080cb64d01SAchin Gupta }
1090cb64d01SAchin Gupta
1100cb64d01SAchin Gupta return manifest_parse_attribute(manifest, fdt, node);
1110cb64d01SAchin Gupta }
1120cb64d01SAchin Gupta
1130cb64d01SAchin Gupta /*******************************************************************************
11452696946SOlivier Deprez * Platform handler to parse a SPM Core manifest.
1150cb64d01SAchin Gupta ******************************************************************************/
plat_spm_core_manifest_load(spmc_manifest_attribute_t * manifest,const void * pm_addr)11652696946SOlivier Deprez int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
11723d5ba86SOlivier Deprez const void *pm_addr)
1180cb64d01SAchin Gupta {
119*55fd56d7SYeoreum Yun #if TRANSFER_LIST && !RESET_TO_BL31
120*55fd56d7SYeoreum Yun int rc;
121*55fd56d7SYeoreum Yun
122*55fd56d7SYeoreum Yun assert(manifest != NULL);
123*55fd56d7SYeoreum Yun assert(pm_addr != NULL);
124*55fd56d7SYeoreum Yun
125*55fd56d7SYeoreum Yun /*
126*55fd56d7SYeoreum Yun * NOTE:
127*55fd56d7SYeoreum Yun * If spmc_manifest is delivered via TRANSFER_LIST,
128*55fd56d7SYeoreum Yun * the spmc_manifest address is already mapped.
129*55fd56d7SYeoreum Yun * So, @pm_addr can be accessed directly.
130*55fd56d7SYeoreum Yun */
131*55fd56d7SYeoreum Yun
132*55fd56d7SYeoreum Yun rc = fdt_check_header(pm_addr);
133*55fd56d7SYeoreum Yun if (rc != 0) {
134*55fd56d7SYeoreum Yun ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
135*55fd56d7SYeoreum Yun return rc;
136*55fd56d7SYeoreum Yun }
137*55fd56d7SYeoreum Yun
138*55fd56d7SYeoreum Yun VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
139*55fd56d7SYeoreum Yun
140*55fd56d7SYeoreum Yun rc = fdt_node_offset_by_compatible(pm_addr, -1,
141*55fd56d7SYeoreum Yun "arm,ffa-core-manifest-1.0");
142*55fd56d7SYeoreum Yun if (rc < 0) {
143*55fd56d7SYeoreum Yun ERROR("Unrecognized SPM Core manifest\n");
144*55fd56d7SYeoreum Yun return rc;
145*55fd56d7SYeoreum Yun }
146*55fd56d7SYeoreum Yun
147*55fd56d7SYeoreum Yun rc = manifest_parse_root(manifest, pm_addr, rc);
148*55fd56d7SYeoreum Yun
149*55fd56d7SYeoreum Yun return rc;
150*55fd56d7SYeoreum Yun #else
15123d5ba86SOlivier Deprez int rc, unmap_ret;
15223d5ba86SOlivier Deprez uintptr_t pm_base, pm_base_align;
15323d5ba86SOlivier Deprez size_t mapped_size;
1540cb64d01SAchin Gupta
1550cb64d01SAchin Gupta assert(manifest != NULL);
15623d5ba86SOlivier Deprez assert(pm_addr != NULL);
1570cb64d01SAchin Gupta
15823d5ba86SOlivier Deprez /*
15923d5ba86SOlivier Deprez * Assume TOS_FW_CONFIG is not necessarily aligned to a page
16023d5ba86SOlivier Deprez * boundary, thus calculate the remaining space between SPMC
16123d5ba86SOlivier Deprez * manifest start address and upper page limit.
16223d5ba86SOlivier Deprez *
16323d5ba86SOlivier Deprez */
16423d5ba86SOlivier Deprez pm_base = (uintptr_t)pm_addr;
16523d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, UP);
166fdd5f9e6SManish Pandey
167fdd5f9e6SManish Pandey if (pm_base == pm_base_align) {
168fdd5f9e6SManish Pandey /* Page aligned */
169fdd5f9e6SManish Pandey mapped_size = PAGE_SIZE;
170fdd5f9e6SManish Pandey } else {
17123d5ba86SOlivier Deprez mapped_size = pm_base_align - pm_base;
172fdd5f9e6SManish Pandey }
1730cb64d01SAchin Gupta
17423d5ba86SOlivier Deprez /* Check space within the page at least maps the FDT header */
17523d5ba86SOlivier Deprez if (mapped_size < sizeof(struct fdt_header)) {
17623d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest.\n");
17723d5ba86SOlivier Deprez return -EINVAL;
17823d5ba86SOlivier Deprez }
17923d5ba86SOlivier Deprez
18023d5ba86SOlivier Deprez /* Map first SPMC manifest page in the SPMD translation regime */
18123d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, DOWN);
18223d5ba86SOlivier Deprez rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
18323d5ba86SOlivier Deprez pm_base_align,
18423d5ba86SOlivier Deprez PAGE_SIZE,
1858c829a92SManish V Badarkhe MT_RO_DATA | EL3_PAS);
1860cb64d01SAchin Gupta if (rc != 0) {
18723d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
18852696946SOlivier Deprez return rc;
1890cb64d01SAchin Gupta }
1900cb64d01SAchin Gupta
19123d5ba86SOlivier Deprez rc = fdt_check_header(pm_addr);
19223d5ba86SOlivier Deprez if (rc != 0) {
19323d5ba86SOlivier Deprez ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
19423d5ba86SOlivier Deprez goto exit_unmap;
19523d5ba86SOlivier Deprez }
19623d5ba86SOlivier Deprez
19723d5ba86SOlivier Deprez /* Check SPMC manifest fits within the upper mapped page boundary */
19823d5ba86SOlivier Deprez if (mapped_size < fdt_totalsize(pm_addr)) {
19923d5ba86SOlivier Deprez ERROR("SPM Core manifest too large.\n");
20023d5ba86SOlivier Deprez rc = -EINVAL;
20123d5ba86SOlivier Deprez goto exit_unmap;
20223d5ba86SOlivier Deprez }
20323d5ba86SOlivier Deprez
20423d5ba86SOlivier Deprez VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
20523d5ba86SOlivier Deprez
20623d5ba86SOlivier Deprez rc = fdt_node_offset_by_compatible(pm_addr, -1,
207662af36dSJ-Alves "arm,ffa-core-manifest-1.0");
20852696946SOlivier Deprez if (rc < 0) {
20952696946SOlivier Deprez ERROR("Unrecognized SPM Core manifest\n");
21023d5ba86SOlivier Deprez goto exit_unmap;
2110cb64d01SAchin Gupta }
2120cb64d01SAchin Gupta
21323d5ba86SOlivier Deprez rc = manifest_parse_root(manifest, pm_addr, rc);
21423d5ba86SOlivier Deprez
21523d5ba86SOlivier Deprez exit_unmap:
21623d5ba86SOlivier Deprez unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
21723d5ba86SOlivier Deprez if (unmap_ret != 0) {
21823d5ba86SOlivier Deprez ERROR("Error while unmapping SPM Core manifest (%d).\n",
21923d5ba86SOlivier Deprez unmap_ret);
22023d5ba86SOlivier Deprez if (rc == 0) {
22123d5ba86SOlivier Deprez rc = unmap_ret;
22223d5ba86SOlivier Deprez }
22323d5ba86SOlivier Deprez }
22423d5ba86SOlivier Deprez
22523d5ba86SOlivier Deprez return rc;
226*55fd56d7SYeoreum Yun #endif
2270cb64d01SAchin Gupta }
228