1 /*
2 * Copyright (c) 2021-2026, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include <common/build_message.h>
7 #include <common/debug.h>
8 #include <lib/gpt_rme/gpt_rme.h>
9 #include <plat/common/platform.h>
10 #include <services/firme_svc.h>
11 #include <services/rmm_core_manifest.h>
12 #include <services/rmmd_svc.h>
13 #include <services/trp/platform_trp.h>
14 #include <trp_helpers.h>
15 #include "trp_private.h"
16
17 #include <platform_def.h>
18
19 #define RMI_ERROR_REALM 2U
20 #define RMI_ERROR_NOT_SUPPORTED 6U
21
22 #define DIR_BIT_SHIFT 0x8
23 #define KEYSET_SHIFT 0xC
24 #define STREAM_ID_MASK 0xFF
25 #define STREAM_ID_SHIFT 0x0
26 #define SUBSTREAM_MASK 0x7
27 #define SUBSTREAM_SHIFT 0x8
28
29 #define KEY_SET 0x0
30 #define DIR_VAL 0x0
31 #define SUBSTREAM_VAL 0x1
32 #define STREAM_ID 0x1
33
34 #define ENCODE_STREAM_INFO(key, dir, substream, stream_id) \
35 (((key & 0x1) << KEYSET_SHIFT) | \
36 ((dir & 0x1) << DIR_BIT_SHIFT) | \
37 ((substream && SUBSTREAM_MASK) << SUBSTREAM_SHIFT) | \
38 ((stream_id && STREAM_ID_MASK) << STREAM_ID_SHIFT))
39
40 /* Parameters received from the previous image */
41 static unsigned int trp_boot_abi_version;
42 static uintptr_t trp_shared_region_start;
43
44 /* Parameters received from boot manifest */
45 uint32_t trp_boot_manifest_version;
46
47 /*******************************************************************************
48 * Setup function for TRP.
49 ******************************************************************************/
trp_setup(uint64_t x0,uint64_t x1,uint64_t x2,uint64_t x3)50 void trp_setup(uint64_t x0,
51 uint64_t x1,
52 uint64_t x2,
53 uint64_t x3)
54 {
55 /*
56 * Validate boot parameters
57 *
58 * According to the Boot Interface ABI v.0.1,
59 * the parameters received from EL3 are:
60 * x0: CPUID (verified earlier, so not used)
61 * x1: Boot Interface version
62 * x2: PLATFORM_CORE_COUNT
63 * x3: Pointer to the shared memory area.
64 */
65
66 (void)x0;
67
68 if (TRP_RMM_EL3_VERSION_GET_MAJOR(x1) != TRP_RMM_EL3_ABI_VERS_MAJOR) {
69 trp_boot_abort(E_RMM_BOOT_VERSION_MISMATCH);
70 }
71
72 if ((void *)x3 == NULL) {
73 trp_boot_abort(E_RMM_BOOT_INVALID_SHARED_BUFFER);
74 }
75
76 if (x2 > TRP_PLATFORM_CORE_COUNT) {
77 trp_boot_abort(E_RMM_BOOT_CPUS_OUT_OF_RANGE);
78 }
79
80 trp_boot_abi_version = x1;
81 trp_shared_region_start = x3;
82 flush_dcache_range((uintptr_t)&trp_boot_abi_version,
83 sizeof(trp_boot_abi_version));
84 flush_dcache_range((uintptr_t)&trp_shared_region_start,
85 sizeof(trp_shared_region_start));
86
87 /* Perform early platform-specific setup */
88 trp_early_platform_setup((struct rmm_manifest *)trp_shared_region_start);
89 }
90
trp_validate_warmboot_args(uint64_t x0,uint64_t x1,uint64_t x2,uint64_t x3)91 int trp_validate_warmboot_args(uint64_t x0, uint64_t x1,
92 uint64_t x2, uint64_t x3)
93 {
94 /*
95 * Validate boot parameters for warm boot
96 *
97 * According to the Boot Interface ABI v.0.1, the parameters
98 * received from EL3 during warm boot are:
99 *
100 * x0: CPUID (verified earlier so not used here)
101 * x1: activation token (ignored)
102 * [x2:x3]: RES0
103 */
104
105 (void)x0;
106 (void)x1;
107
108 if ((x2 | x3) != 0UL) {
109 ERROR("TRP: extra warmboot arguments not 0: x2=0x%lx, x3=0x%lx\n",
110 x2, x3);
111 return E_RMM_BOOT_UNKNOWN;
112 }
113
114 return 0;
115 }
116
117 /* Main function for TRP */
trp_main(void)118 void trp_main(void)
119 {
120 NOTICE("TRP: %s\n", build_version_string);
121 NOTICE("TRP: %s\n", build_message);
122 NOTICE("TRP: Supported RMM-EL3 Interface ABI: v.%u.%u\n",
123 TRP_RMM_EL3_ABI_VERS_MAJOR, TRP_RMM_EL3_ABI_VERS_MINOR);
124 NOTICE("TRP: Boot Manifest Version: v.%u.%u\n",
125 RMMD_GET_MANIFEST_VERSION_MAJOR(trp_boot_manifest_version),
126 RMMD_GET_MANIFEST_VERSION_MINOR(trp_boot_manifest_version));
127 INFO("TRP: Memory base: 0x%lx\n", (unsigned long)RMM_BASE);
128 INFO("TRP: Shared region base address: 0x%lx\n",
129 (unsigned long)trp_shared_region_start);
130 INFO("TRP: Total size: 0x%lx bytes\n",
131 (unsigned long)(RMM_END - RMM_BASE));
132 INFO("TRP: RMM-EL3 Interface ABI reported by EL3: v.%u.%u\n",
133 TRP_RMM_EL3_VERSION_GET_MAJOR(trp_boot_abi_version),
134 TRP_RMM_EL3_VERSION_GET_MINOR(trp_boot_abi_version));
135 }
136
137 /*******************************************************************************
138 * Returning RMI version back to Normal World
139 ******************************************************************************/
trp_ret_rmi_version(unsigned long long rmi_version,struct trp_smc_result * smc_ret)140 static void trp_ret_rmi_version(unsigned long long rmi_version,
141 struct trp_smc_result *smc_ret)
142 {
143 if (rmi_version != RMI_ABI_VERSION) {
144 smc_ret->x[0] = RMI_ERROR_INPUT;
145 } else {
146 smc_ret->x[0] = RMI_SUCCESS;
147 }
148 VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR,
149 RMI_ABI_VERSION_MINOR);
150 smc_ret->x[1] = RMI_ABI_VERSION;
151 smc_ret->x[2] = RMI_ABI_VERSION;
152 }
153
154 /*******************************************************************************
155 * Transitioning granule of NON-SECURE type to REALM type
156 ******************************************************************************/
trp_asc_mark_realm(unsigned long long x1,struct trp_smc_result * smc_ret)157 static void trp_asc_mark_realm(unsigned long long x1,
158 struct trp_smc_result *smc_ret)
159 {
160 VERBOSE("Delegating granule 0x%llx\n", x1);
161
162 #if FIRME_SUPPORT
163 smc_ret->x[0] = trp_smc(set_smc_args(FIRME_GM_GPI_SET_FID, x1, 1UL,
164 GPT_GPI_REALM, 0UL, 0UL, 0UL, 0UL,
165 0UL, 0UL, 0UL, 0UL));
166 #else
167 smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_DELEGATE, x1,
168 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
169 #endif
170
171 if (smc_ret->x[0] != 0ULL) {
172 ERROR("Granule transition from NON-SECURE type to REALM type "
173 "failed 0x%llx\n", smc_ret->x[0]);
174
175 /*
176 * x[1] is not a return parameter for GRANULE_DELEGATE,
177 * but populating it is harmless and simplifies the implementation.
178 */
179 smc_ret->x[1] = x1;
180 return;
181 }
182 smc_ret->x[1] = x1 + PAGE_SIZE_4KB;
183 }
184
185 /*******************************************************************************
186 * Transitioning granule of REALM type to NON-SECURE type
187 ******************************************************************************/
trp_asc_mark_nonsecure(unsigned long long x1,struct trp_smc_result * smc_ret)188 static void trp_asc_mark_nonsecure(unsigned long long x1,
189 struct trp_smc_result *smc_ret)
190 {
191 VERBOSE("Undelegating granule 0x%llx\n", x1);
192
193 #if FIRME_SUPPORT
194 smc_ret->x[0] =
195 trp_smc(set_smc_args(FIRME_GM_GPI_SET_FID, x1, 1UL, GPT_GPI_NS,
196 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
197 #else
198 smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_UNDELEGATE, x1,
199 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
200 #endif
201
202 if (smc_ret->x[0] != 0ULL) {
203 ERROR("Granule transition from REALM type to NON-SECURE type "
204 "failed 0x%llx\n", smc_ret->x[0]);
205
206 /*
207 * x[1] is not a return parameter for GRANULE_UNDELEGATE,
208 * but populating it is harmless and simplifies the implementation.
209 */
210 smc_ret->x[1] = x1;
211 return;
212 }
213 smc_ret->x[1] = x1 + PAGE_SIZE_4KB;
214 }
215
216 /*******************************************************************************
217 * Test the IDE Key management interface
218 ******************************************************************************/
trp_ide_keymgmt_interface_fn(unsigned long long x1,unsigned long long x2,struct trp_smc_result * smc_ret)219 static void trp_ide_keymgmt_interface_fn(unsigned long long x1, unsigned long long x2,
220 struct trp_smc_result *smc_ret)
221 {
222 uint64_t ecam_address = 0U, rp_id = 0U, ide_stream_info;
223 uint64_t keyqw0, keyqw1, keyqw2, keyqw3;
224 uint64_t ifvqw0, ifvqw1;
225 int return_value;
226
227 #if RMMD_ENABLE_IDE_KEY_PROG
228 trp_get_test_rootport(&ecam_address, &rp_id);
229 #endif /* RMMD_ENABLE_IDE_KEY_PROG */
230 /*
231 * Dummy values for testing:
232 * Key set = 0x0
233 * Dir = 0x0
234 * Substream = 0x1
235 * Stream ID = 0x1
236 */
237 ide_stream_info = ENCODE_STREAM_INFO(KEY_SET, DIR_VAL, SUBSTREAM_VAL, STREAM_ID);
238
239 /* Dummy key and IV values for testing */
240 keyqw0 = 0xA1B2C3D4E5F60708;
241 keyqw1 = 0x1122334455667788;
242 keyqw2 = 0xDEADBEEFCAFEBABE;
243 keyqw3 = 0x1234567890ABCDEF;
244 ifvqw0 = 0xABCDEF0123456789;
245 ifvqw1 = 0x9876543210FEDCBA;
246
247 return_value = trp_smc(set_smc_args(RMM_IDE_KEY_PROG, ecam_address, rp_id,
248 ide_stream_info, keyqw0, keyqw1, keyqw2, keyqw3, ifvqw0,
249 ifvqw1, 0UL, 0UL));
250
251 INFO("return value from RMM_IDE_KEY_PROG = %d\n", return_value);
252
253 return_value = trp_smc(set_smc_args(RMM_IDE_KEY_SET_GO, ecam_address, rp_id,
254 ide_stream_info, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
255
256 INFO("return value from RMM_IDE_KEY_SET_GO = %d\n", return_value);
257
258 return_value = trp_smc(set_smc_args(RMM_IDE_KEY_SET_STOP, ecam_address, rp_id,
259 ide_stream_info, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
260
261 INFO("return value from RMM_IDE_KEY_SET_STOP = %d\n", return_value);
262
263 return_value = trp_smc(set_smc_args(RMM_IDE_KM_PULL_RESPONSE, ecam_address, rp_id,
264 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
265
266 INFO("return value from RMM_IDE_KEY_SET_STOP = %d\n", return_value);
267
268 smc_ret->x[0] = RMI_ERROR_NOT_SUPPORTED;
269
270 }
271
272 /*******************************************************************************
273 * Main RMI SMC handler function
274 ******************************************************************************/
trp_rmi_handler(unsigned long fid,unsigned long long x1,unsigned long long x2,unsigned long long x3,unsigned long long x4,unsigned long long x5,unsigned long long x6,unsigned long long x7,struct trp_smc_result * smc_ret)275 void trp_rmi_handler(unsigned long fid,
276 unsigned long long x1, unsigned long long x2,
277 unsigned long long x3, unsigned long long x4,
278 unsigned long long x5, unsigned long long x6,
279 unsigned long long x7,
280 struct trp_smc_result *smc_ret)
281 {
282 /* Not used in the current implementation */
283 (void)x2;
284 (void)x3;
285 (void)x4;
286 (void)x5;
287 (void)x6;
288 (void)x7;
289
290 switch (fid) {
291 case RMI_RMM_REQ_VERSION:
292 trp_ret_rmi_version(x1, smc_ret);
293 break;
294 case RMI_RMM_ACTIVATE:
295 smc_ret->x[0] = RMI_SUCCESS;
296 break;
297 case RMI_RMM_GRANULE_DELEGATE:
298 trp_asc_mark_realm(x1, smc_ret);
299 break;
300 case RMI_RMM_GRANULE_UNDELEGATE:
301 trp_asc_mark_nonsecure(x1, smc_ret);
302 break;
303 case RMI_RMM_GRANULE_RANGE_DELEGATE:
304 trp_asc_mark_realm(x1, smc_ret);
305 break;
306 case RMI_RMM_GRANULE_RANGE_UNDELEGATE:
307 trp_asc_mark_nonsecure(x1, smc_ret);
308 break;
309 case RMI_RMM_PDEV_CREATE:
310 trp_ide_keymgmt_interface_fn(x1, x2, smc_ret);
311 break;
312 case RMI_RMM_CONFIG_SET:
313 case RMI_RMM_CONFIG_GET:
314 smc_ret->x[0] = RMI_SUCCESS;
315 break;
316 default:
317 ERROR("Invalid SMC code to %s, FID %lx\n", __func__, fid);
318 smc_ret->x[0] = SMC_UNK;
319 }
320 }
321