plat_spmd_manifest.c 4.99 KB
Newer Older
1
2
3
4
5
6
7
/*
 * Copyright (c) 2020, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>
Olivier Deprez's avatar
Olivier Deprez committed
8
#include <errno.h>
9
10
11
12
13
#include <string.h>
#include <libfdt.h>

#include <common/debug.h>
#include <common/fdt_wrappers.h>
14
#include <lib/xlat_tables/xlat_tables_v2.h>
15
16
17
#include <platform_def.h>
#include <services/spm_core_manifest.h>

Olivier Deprez's avatar
Olivier Deprez committed
18
19
#define ATTRIBUTE_ROOT_NODE_STR "attribute"

20
/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
21
 * SPMC attribute node parser
22
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
23
static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
24
25
26
				    const void *fdt,
				    int node)
{
27
	uint32_t val32;
Olivier Deprez's avatar
Olivier Deprez committed
28
	int rc;
29

Olivier Deprez's avatar
Olivier Deprez committed
30
	assert((attr != NULL) && (fdt != NULL));
31

32
	rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
Olivier Deprez's avatar
Olivier Deprez committed
33
	if (rc != 0) {
J-Alves's avatar
J-Alves committed
34
		ERROR("Missing FFA %s version in SPM Core manifest.\n",
Olivier Deprez's avatar
Olivier Deprez committed
35
36
			"major");
		return rc;
37
38
	}

39
	rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
Olivier Deprez's avatar
Olivier Deprez committed
40
	if (rc != 0) {
J-Alves's avatar
J-Alves committed
41
		ERROR("Missing FFA %s version in SPM Core manifest.\n",
Olivier Deprez's avatar
Olivier Deprez committed
42
43
			"minor");
		return rc;
44
45
	}

46
	rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
Olivier Deprez's avatar
Olivier Deprez committed
47
	if (rc != 0) {
48
		ERROR("Missing SPMC ID in manifest.\n");
Olivier Deprez's avatar
Olivier Deprez committed
49
		return rc;
50
	}
Olivier Deprez's avatar
Olivier Deprez committed
51
52

	attr->spmc_id = val32 & 0xffff;
53

54
	rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
Olivier Deprez's avatar
Olivier Deprez committed
55
56
57
58
	if (rc != 0) {
		NOTICE("%s not specified in SPM Core manifest.\n",
			"Execution state");
	}
59

60
	rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
Olivier Deprez's avatar
Olivier Deprez committed
61
62
63
64
	if (rc != 0) {
		NOTICE("%s not specified in SPM Core manifest.\n",
			"Binary size");
	}
65

66
	rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
Olivier Deprez's avatar
Olivier Deprez committed
67
68
69
70
	if (rc != 0) {
		NOTICE("%s not specified in SPM Core manifest.\n",
			"Load address");
	}
71

72
	rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
Olivier Deprez's avatar
Olivier Deprez committed
73
74
75
76
	if (rc != 0) {
		NOTICE("%s not specified in SPM Core manifest.\n",
			"Entry point");
	}
77

Olivier Deprez's avatar
Olivier Deprez committed
78
79
80
	VERBOSE("SPM Core manifest attribute section:\n");
	VERBOSE("  version: %u.%u\n", attr->major_version, attr->minor_version);
	VERBOSE("  spmc_id: 0x%x\n", attr->spmc_id);
81
82
83
84
85
86
87
88
89
90
	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
	VERBOSE("  load_address: 0x%llx\n", attr->load_address);
	VERBOSE("  entrypoint: 0x%llx\n", attr->entrypoint);

	return 0;
}

/*******************************************************************************
 * Root node handler
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
91
92
93
static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
			       const void *fdt,
			       int root)
94
95
96
{
	int node;

Olivier Deprez's avatar
Olivier Deprez committed
97
98
99
100
	assert(manifest != NULL);

	node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
		sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
101
	if (node < 0) {
Olivier Deprez's avatar
Olivier Deprez committed
102
103
104
		ERROR("Root node doesn't contain subnode '%s'\n",
			ATTRIBUTE_ROOT_NODE_STR);
		return node;
105
106
107
108
109
110
	}

	return manifest_parse_attribute(manifest, fdt, node);
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
111
 * Platform handler to parse a SPM Core manifest.
112
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
113
int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
114
				const void *pm_addr)
115
{
116
117
118
	int rc, unmap_ret;
	uintptr_t pm_base, pm_base_align;
	size_t mapped_size;
119
120

	assert(manifest != NULL);
121
122
123
124
125
126
127
128
129
130
	assert(pm_addr != NULL);

	/*
	 * Assume TOS_FW_CONFIG is not necessarily aligned to a page
	 * boundary, thus calculate the remaining space between SPMC
	 * manifest start address and upper page limit.
	 *
	 */
	pm_base = (uintptr_t)pm_addr;
	pm_base_align = page_align(pm_base, UP);
131
132
133
134
135
136
137

	if (pm_base == pm_base_align) {
		/* Page aligned */
		mapped_size = PAGE_SIZE;
	} else {
		mapped_size = pm_base_align - pm_base;
	}
138
139
140
141
142
143

	/* Check space within the page at least maps the FDT header */
	if (mapped_size < sizeof(struct fdt_header)) {
		ERROR("Error while mapping SPM Core manifest.\n");
		return -EINVAL;
	}
144

145
146
147
148
149
150
151
152
153
154
	/* Map first SPMC manifest page in the SPMD translation regime */
	pm_base_align = page_align(pm_base, DOWN);
	rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
				     pm_base_align,
				     PAGE_SIZE,
				     MT_RO_DATA);
	if (rc != 0) {
		ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
		return rc;
	}
155

156
	rc = fdt_check_header(pm_addr);
157
	if (rc != 0) {
Olivier Deprez's avatar
Olivier Deprez committed
158
		ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
159
		goto exit_unmap;
160
161
	}

162
163
164
165
166
167
168
169
170
171
	/* Check SPMC manifest fits within the upper mapped page boundary */
	if (mapped_size < fdt_totalsize(pm_addr)) {
		ERROR("SPM Core manifest too large.\n");
		rc = -EINVAL;
		goto exit_unmap;
	}

	VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);

	rc = fdt_node_offset_by_compatible(pm_addr, -1,
J-Alves's avatar
J-Alves committed
172
				"arm,ffa-core-manifest-1.0");
Olivier Deprez's avatar
Olivier Deprez committed
173
174
	if (rc < 0) {
		ERROR("Unrecognized SPM Core manifest\n");
175
176
177
178
179
180
181
182
183
184
185
186
187
		goto exit_unmap;
	}

	rc = manifest_parse_root(manifest, pm_addr, rc);

exit_unmap:
	unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
	if (unmap_ret != 0) {
		ERROR("Error while unmapping SPM Core manifest (%d).\n",
			unmap_ret);
		if (rc == 0) {
			rc = unmap_ret;
		}
188
189
	}

190
	return rc;
191
}