xref: /rk3399_ARM-atf/plat/common/plat_spmd_manifest.c (revision 0aa9f3c0f2f2ff675c3c12ae5ac6ceb475d6a16f)
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 
132 	if (pm_base == pm_base_align) {
133 		/* Page aligned */
134 		mapped_size = PAGE_SIZE;
135 	} else {
136 		mapped_size = pm_base_align - pm_base;
137 	}
138 
139 	/* Check space within the page at least maps the FDT header */
140 	if (mapped_size < sizeof(struct fdt_header)) {
141 		ERROR("Error while mapping SPM Core manifest.\n");
142 		return -EINVAL;
143 	}
144 
145 	/* Map first SPMC manifest page in the SPMD translation regime */
146 	pm_base_align = page_align(pm_base, DOWN);
147 	rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
148 				     pm_base_align,
149 				     PAGE_SIZE,
150 				     MT_RO_DATA);
151 	if (rc != 0) {
152 		ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
153 		return rc;
154 	}
155 
156 	rc = fdt_check_header(pm_addr);
157 	if (rc != 0) {
158 		ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
159 		goto exit_unmap;
160 	}
161 
162 	/* Check SPMC manifest fits within the upper mapped page boundary */
163 	if (mapped_size < fdt_totalsize(pm_addr)) {
164 		ERROR("SPM Core manifest too large.\n");
165 		rc = -EINVAL;
166 		goto exit_unmap;
167 	}
168 
169 	VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
170 
171 	rc = fdt_node_offset_by_compatible(pm_addr, -1,
172 				"arm,ffa-core-manifest-1.0");
173 	if (rc < 0) {
174 		ERROR("Unrecognized SPM Core manifest\n");
175 		goto exit_unmap;
176 	}
177 
178 	rc = manifest_parse_root(manifest, pm_addr, rc);
179 
180 exit_unmap:
181 	unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
182 	if (unmap_ret != 0) {
183 		ERROR("Error while unmapping SPM Core manifest (%d).\n",
184 			unmap_ret);
185 		if (rc == 0) {
186 			rc = unmap_ret;
187 		}
188 	}
189 
190 	return rc;
191 }
192