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