xref: /rk3399_ARM-atf/plat/common/plat_spmd_manifest.c (revision 0396bcbc6ae75a71489c078ae43f6f549abd5be4)
1 /*
2  * Copyright (c) 2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <libfdt.h>
11 
12 #include <common/debug.h>
13 #include <common/fdt_wrappers.h>
14 #include <lib/xlat_tables/xlat_tables_v2.h>
15 #include <platform_def.h>
16 #include <services/spm_core_manifest.h>
17 
18 #define ATTRIBUTE_ROOT_NODE_STR "attribute"
19 
20 /*******************************************************************************
21  * SPMC attribute node parser
22  ******************************************************************************/
23 static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
24 				    const void *fdt,
25 				    int node)
26 {
27 	uint32_t val32;
28 	int rc;
29 
30 	assert((attr != NULL) && (fdt != NULL));
31 
32 	rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
33 	if (rc != 0) {
34 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
35 			"major");
36 		return rc;
37 	}
38 
39 	rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
40 	if (rc != 0) {
41 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
42 			"minor");
43 		return rc;
44 	}
45 
46 	rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
47 	if (rc != 0) {
48 		ERROR("Missing SPMC ID in manifest.\n");
49 		return rc;
50 	}
51 
52 	attr->spmc_id = val32 & 0xffff;
53 
54 	rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
55 	if (rc != 0) {
56 		NOTICE("%s not specified in SPM Core manifest.\n",
57 			"Execution state");
58 	}
59 
60 	rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
61 	if (rc != 0) {
62 		NOTICE("%s not specified in SPM Core manifest.\n",
63 			"Binary size");
64 	}
65 
66 	rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
67 	if (rc != 0) {
68 		NOTICE("%s not specified in SPM Core manifest.\n",
69 			"Load address");
70 	}
71 
72 	rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
73 	if (rc != 0) {
74 		NOTICE("%s not specified in SPM Core manifest.\n",
75 			"Entry point");
76 	}
77 
78 	VERBOSE("SPM Core manifest attribute section:\n");
79 	VERBOSE("  version: %u.%u\n", attr->major_version, attr->minor_version);
80 	VERBOSE("  spmc_id: 0x%x\n", attr->spmc_id);
81 	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
82 	VERBOSE("  load_address: 0x%llx\n", attr->load_address);
83 	VERBOSE("  entrypoint: 0x%llx\n", attr->entrypoint);
84 
85 	return 0;
86 }
87 
88 /*******************************************************************************
89  * Root node handler
90  ******************************************************************************/
91 static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
92 			       const void *fdt,
93 			       int root)
94 {
95 	int node;
96 
97 	assert(manifest != NULL);
98 
99 	node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
100 		sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
101 	if (node < 0) {
102 		ERROR("Root node doesn't contain subnode '%s'\n",
103 			ATTRIBUTE_ROOT_NODE_STR);
104 		return node;
105 	}
106 
107 	return manifest_parse_attribute(manifest, fdt, node);
108 }
109 
110 /*******************************************************************************
111  * Platform handler to parse a SPM Core manifest.
112  ******************************************************************************/
113 int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
114 				const void *pm_addr)
115 {
116 	int rc, unmap_ret;
117 	uintptr_t pm_base, pm_base_align;
118 	size_t mapped_size;
119 
120 	assert(manifest != NULL);
121 	assert(pm_addr != NULL);
122 
123 	/*
124 	 * Assume TOS_FW_CONFIG is not necessarily aligned to a page
125 	 * boundary, thus calculate the remaining space between SPMC
126 	 * manifest start address and upper page limit.
127 	 *
128 	 */
129 	pm_base = (uintptr_t)pm_addr;
130 	pm_base_align = page_align(pm_base, UP);
131 	mapped_size = pm_base_align - pm_base;
132 
133 	/* Check space within the page at least maps the FDT header */
134 	if (mapped_size < sizeof(struct fdt_header)) {
135 		ERROR("Error while mapping SPM Core manifest.\n");
136 		return -EINVAL;
137 	}
138 
139 	/* Map first SPMC manifest page in the SPMD translation regime */
140 	pm_base_align = page_align(pm_base, DOWN);
141 	rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
142 				     pm_base_align,
143 				     PAGE_SIZE,
144 				     MT_RO_DATA);
145 	if (rc != 0) {
146 		ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
147 		return rc;
148 	}
149 
150 	rc = fdt_check_header(pm_addr);
151 	if (rc != 0) {
152 		ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
153 		goto exit_unmap;
154 	}
155 
156 	/* Check SPMC manifest fits within the upper mapped page boundary */
157 	if (mapped_size < fdt_totalsize(pm_addr)) {
158 		ERROR("SPM Core manifest too large.\n");
159 		rc = -EINVAL;
160 		goto exit_unmap;
161 	}
162 
163 	VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
164 
165 	rc = fdt_node_offset_by_compatible(pm_addr, -1,
166 				"arm,ffa-core-manifest-1.0");
167 	if (rc < 0) {
168 		ERROR("Unrecognized SPM Core manifest\n");
169 		goto exit_unmap;
170 	}
171 
172 	rc = manifest_parse_root(manifest, pm_addr, rc);
173 
174 exit_unmap:
175 	unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
176 	if (unmap_ret != 0) {
177 		ERROR("Error while unmapping SPM Core manifest (%d).\n",
178 			unmap_ret);
179 		if (rc == 0) {
180 			rc = unmap_ret;
181 		}
182 	}
183 
184 	return rc;
185 }
186