blob: 69b9a23fb53b8d4f3beecb0b153ebef16ab96e6b [file] [log] [blame]
Antonio Nino Diazb86edcb2018-10-30 11:12:42 +00001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <debug.h>
9#include <fdt_wrappers.h>
10#include <libfdt.h>
11#include <platform_def.h>
12#include <sp_res_desc.h>
13#include <string.h>
14#include <object_pool.h>
15
16/*******************************************************************************
17 * Resource pool
18 ******************************************************************************/
19static struct sp_rd_sect_mem_region rd_mem_regions[PLAT_SPM_MEM_REGIONS_MAX];
20static OBJECT_POOL_ARRAY(rd_mem_regions_pool, rd_mem_regions);
21
22static struct sp_rd_sect_notification rd_notifs[PLAT_SPM_NOTIFICATIONS_MAX];
23static OBJECT_POOL_ARRAY(rd_notifs_pool, rd_notifs);
24
25static struct sp_rd_sect_service rd_services[PLAT_SPM_SERVICES_MAX];
26static OBJECT_POOL_ARRAY(rd_services_pool, rd_services);
27
28/*******************************************************************************
29 * Attribute section handler
30 ******************************************************************************/
31static void rd_parse_attribute(struct sp_rd_sect_attribute *attr,
32 const void *fdt, int node)
33{
34 int rc = 0;
35
36 /* The minimum size that can be read from the DTB is 32-bit. */
37 uint32_t version, sp_type, runtime_el, exec_type;
38 uint32_t panic_policy, xlat_granule;
39
40 rc |= fdtw_read_cells(fdt, node, "version", 1, &version);
41
42 if (version != 1) {
43 ERROR("Unsupported resource description version: 0x%x\n",
44 version);
45 panic();
46 }
47
48 rc |= fdtw_read_cells(fdt, node, "sp_type", 1, &sp_type);
49 rc |= fdtw_read_cells(fdt, node, "pe_mpidr", 1, &attr->pe_mpidr);
50 rc |= fdtw_read_cells(fdt, node, "runtime_el", 1, &runtime_el);
51 rc |= fdtw_read_cells(fdt, node, "exec_type", 1, &exec_type);
52 rc |= fdtw_read_cells(fdt, node, "panic_policy", 1, &panic_policy);
53 rc |= fdtw_read_cells(fdt, node, "xlat_granule", 1, &xlat_granule);
54 rc |= fdtw_read_cells(fdt, node, "binary_size", 1, &attr->binary_size);
55 rc |= fdtw_read_cells(fdt, node, "load_address", 2, &attr->load_address);
56 rc |= fdtw_read_cells(fdt, node, "entrypoint", 2, &attr->entrypoint);
57
58 attr->version = version;
59 attr->sp_type = sp_type;
60 attr->runtime_el = runtime_el;
61 attr->exec_type = exec_type;
62 attr->panic_policy = panic_policy;
63 attr->xlat_granule = xlat_granule;
64
65 VERBOSE(" Attribute Section:\n");
66 VERBOSE(" version: 0x%x\n", version);
67 VERBOSE(" sp_type: 0x%x\n", sp_type);
68 VERBOSE(" pe_mpidr: 0x%x\n", attr->pe_mpidr);
69 VERBOSE(" runtime_el: 0x%x\n", runtime_el);
70 VERBOSE(" exec_type: 0x%x\n", exec_type);
71 VERBOSE(" panic_policy: 0x%x\n", panic_policy);
72 VERBOSE(" xlat_granule: 0x%x\n", xlat_granule);
73 VERBOSE(" binary_size: 0x%x\n", attr->binary_size);
74 VERBOSE(" load_address: 0x%llx\n", attr->load_address);
75 VERBOSE(" entrypoint: 0x%llx\n", attr->entrypoint);
76
77 if (rc) {
78 ERROR("Failed to read attribute node elements.\n");
79 panic();
80 }
81}
82
83/*******************************************************************************
84 * Memory regions section handlers
85 ******************************************************************************/
86static void rd_parse_memory_region(struct sp_rd_sect_mem_region *rdmem,
87 const void *fdt, int node)
88{
89 int rc = 0;
90 char name[RD_MEM_REGION_NAME_LEN];
91
92 rc |= fdtw_read_string(fdt, node, "str", (char *)&name, sizeof(name));
93 rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdmem->attr);
94 rc |= fdtw_read_cells(fdt, node, "base", 2, &rdmem->base);
95 rc |= fdtw_read_cells(fdt, node, "size", 2, &rdmem->size);
96
97 size_t len = strlcpy(rdmem->name, name, RD_MEM_REGION_NAME_LEN);
98
99 if (len >= RD_MEM_REGION_NAME_LEN) {
100 WARN("Memory region name truncated: '%s'\n", name);
101 }
102
103 VERBOSE(" Memory Region:\n");
104 VERBOSE(" name: '%s'\n", rdmem->name);
105 VERBOSE(" attr: 0x%x\n", rdmem->attr);
106 VERBOSE(" base: 0x%llx\n", rdmem->base);
107 VERBOSE(" size: 0x%llx\n", rdmem->size);
108
109 if (rc) {
110 ERROR("Failed to read mem_region node elements.\n");
111 panic();
112 }
113}
114
115static void rd_parse_memory_regions(struct sp_res_desc *rd, const void *fdt,
116 int node)
117{
118 int child;
119 struct sp_rd_sect_mem_region *rdmem, *old_rdmem;
120
121 fdt_for_each_subnode(child, fdt, node) {
122 rdmem = pool_alloc(&rd_mem_regions_pool);
123
124 /* Add element to the start of the list */
125 old_rdmem = rd->mem_region;
126 rd->mem_region = rdmem;
127 rdmem->next = old_rdmem;
128
129 rd_parse_memory_region(rdmem, fdt, child);
130 }
131
132 if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
133 ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
134 panic();
135 }
136}
137
138/*******************************************************************************
139 * Notifications section handlers
140 ******************************************************************************/
141static void rd_parse_notification(struct sp_rd_sect_notification *rdnot,
142 const void *fdt, int node)
143{
144 int rc = 0;
145
146 rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdnot->attr);
147 rc |= fdtw_read_cells(fdt, node, "pe", 1, &rdnot->pe);
148
149 VERBOSE(" Notification:\n");
150 VERBOSE(" attr: 0x%x\n", rdnot->attr);
151 VERBOSE(" pe: 0x%x\n", rdnot->pe);
152
153 if (rc) {
154 ERROR("Failed to read notification node elements.\n");
155 panic();
156 }
157}
158
159static void rd_parse_notifications(struct sp_res_desc *rd, const void *fdt, int node)
160{
161 int child;
162 struct sp_rd_sect_notification *rdnot, *old_rdnot;
163
164 fdt_for_each_subnode(child, fdt, node) {
165 rdnot = pool_alloc(&rd_notifs_pool);
166
167 /* Add element to the start of the list */
168 old_rdnot = rd->notification;
169 rd->notification = rdnot;
170 rdnot->next = old_rdnot;
171
172 rd_parse_notification(rdnot, fdt, child);
173 }
174
175 if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
176 ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, child);
177 panic();
178 }
179}
180
181/*******************************************************************************
182 * Services section handlers
183 ******************************************************************************/
184static void rd_parse_service(struct sp_rd_sect_service *rdsvc, const void *fdt,
185 int node)
186{
187 int rc = 0;
188
189 /* The minimum size that can be read from the DTB is 32-bit. */
190 uint32_t accessibility, request_type, connection_quota;
191
192 rc |= fdtw_read_array(fdt, node, "uuid", 4, &rdsvc->uuid);
193 rc |= fdtw_read_cells(fdt, node, "accessibility", 1, &accessibility);
194 rc |= fdtw_read_cells(fdt, node, "request_type", 1, &request_type);
195 rc |= fdtw_read_cells(fdt, node, "connection_quota", 1, &connection_quota);
196 rc |= fdtw_read_cells(fdt, node, "sec_mem_size", 1, &rdsvc->secure_mem_size);
197 rc |= fdtw_read_cells(fdt, node, "interrupt_num", 1, &rdsvc->interrupt_num);
198
199 rdsvc->accessibility = accessibility;
200 rdsvc->request_type = request_type;
201 rdsvc->connection_quota = connection_quota;
202
203 VERBOSE(" Service:\n");
204 VERBOSE(" uuid: 0x%08x 0x%08x 0x%08x 0x%08x\n", rdsvc->uuid[0],
205 rdsvc->uuid[1], rdsvc->uuid[2], rdsvc->uuid[3]);
206 VERBOSE(" accessibility: 0x%x\n", accessibility);
207 VERBOSE(" request_type: 0x%x\n", request_type);
208 VERBOSE(" connection_quota: 0x%x\n", connection_quota);
209 VERBOSE(" secure_memory_size: 0x%x\n", rdsvc->secure_mem_size);
210 VERBOSE(" interrupt_num: 0x%x\n", rdsvc->interrupt_num);
211
212 if (rc) {
213 ERROR("Failed to read attribute node elements.\n");
214 panic();
215 }
216}
217
218static void rd_parse_services(struct sp_res_desc *rd, const void *fdt, int node)
219{
220 int child;
221 struct sp_rd_sect_service *rdsvc, *old_rdsvc;
222
223 fdt_for_each_subnode(child, fdt, node) {
224 rdsvc = pool_alloc(&rd_services_pool);
225
226 /* Add element to the start of the list */
227 old_rdsvc = rd->service;
228 rd->service = rdsvc;
229 rdsvc->next = old_rdsvc;
230
231 rd_parse_service(rdsvc, fdt, child);
232 }
233
234 if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
235 ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
236 panic();
237 }
238}
239
240/*******************************************************************************
241 * Root node handler
242 ******************************************************************************/
243static void rd_parse_root(struct sp_res_desc *rd, const void *fdt, int root)
244{
245 int node;
246 char *str;
247
248 str = "attribute";
249 node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
250 if (node < 0) {
251 ERROR("Root node doesn't contain subnode '%s'\n", str);
252 panic();
253 } else {
254 rd_parse_attribute(&rd->attribute, fdt, node);
255 }
256
257 str = "memory_regions";
258 node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
259 if (node < 0) {
260 ERROR("Root node doesn't contain subnode '%s'\n", str);
261 panic();
262 } else {
263 rd_parse_memory_regions(rd, fdt, node);
264 }
265
266 str = "notifications";
267 node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
268 if (node < 0) {
269 WARN("Root node doesn't contain subnode '%s'\n", str);
270 } else {
271 rd_parse_notifications(rd, fdt, node);
272 }
273
274 str = "services";
275 node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
276 if (node < 0) {
277 WARN("Root node doesn't contain subnode '%s'\n", str);
278 } else {
279 rd_parse_services(rd, fdt, node);
280 }
281}
282
283/*******************************************************************************
284 * Platform handler to load resource descriptor blobs into the active Secure
285 * Partition context.
286 ******************************************************************************/
287int plat_spm_sp_rd_load(struct sp_res_desc *rd, const void *ptr, size_t size)
288{
289 int rc;
290 int root_node;
291
292 assert(rd != NULL);
293 assert(ptr != NULL);
294
295 INFO("Reading RD blob at address %p\n", ptr);
296
297 rc = fdt_check_header(ptr);
298 if (rc != 0) {
299 ERROR("Wrong format for resource descriptor blob (%d).\n", rc);
300 return -1;
301 }
302
303 root_node = fdt_node_offset_by_compatible(ptr, -1, "arm,sp_rd");
304 if (root_node < 0) {
305 ERROR("Unrecognized resource descriptor blob (%d)\n", rc);
306 return -1;
307 }
308
309 rd_parse_root(rd, ptr, root_node);
310
311 return 0;
312}