150a3056aSZelalem Aweke /*
28b3a89faSSona Mathew * Copyright (c) 2021-2025, Arm Limited and Contributors. All rights reserved.
350a3056aSZelalem Aweke *
450a3056aSZelalem Aweke * SPDX-License-Identifier: BSD-3-Clause
550a3056aSZelalem Aweke */
650a3056aSZelalem Aweke
7758ccb80SChris Kay #include <common/build_message.h>
850a3056aSZelalem Aweke #include <common/debug.h>
950a3056aSZelalem Aweke #include <plat/common/platform.h>
101d0ca40eSJavier Almansa Sobrino #include <services/rmm_core_manifest.h>
11319fb084SSoby Mathew #include <services/rmmd_svc.h>
1250a3056aSZelalem Aweke #include <services/trp/platform_trp.h>
131d0ca40eSJavier Almansa Sobrino #include <trp_helpers.h>
141d0ca40eSJavier Almansa Sobrino #include "trp_private.h"
1550a3056aSZelalem Aweke
1650a3056aSZelalem Aweke #include <platform_def.h>
1750a3056aSZelalem Aweke
188b3a89faSSona Mathew #define RMI_ERROR_REALM 2U
198b3a89faSSona Mathew #define RMI_ERROR_NOT_SUPPORTED 6U
208b3a89faSSona Mathew
218b3a89faSSona Mathew #define DIR_BIT_SHIFT 0x8
228b3a89faSSona Mathew #define KEYSET_SHIFT 0xC
238b3a89faSSona Mathew #define STREAM_ID_MASK 0xFF
248b3a89faSSona Mathew #define STREAM_ID_SHIFT 0x0
258b3a89faSSona Mathew #define SUBSTREAM_MASK 0x7
268b3a89faSSona Mathew #define SUBSTREAM_SHIFT 0x8
278b3a89faSSona Mathew
288b3a89faSSona Mathew #define KEY_SET 0x0
298b3a89faSSona Mathew #define DIR_VAL 0x0
308b3a89faSSona Mathew #define SUBSTREAM_VAL 0x1
318b3a89faSSona Mathew #define STREAM_ID 0x1
328b3a89faSSona Mathew
338b3a89faSSona Mathew #define ENCODE_STREAM_INFO(key, dir, substream, stream_id) \
348b3a89faSSona Mathew (((key & 0x1) << KEYSET_SHIFT) | \
358b3a89faSSona Mathew ((dir & 0x1) << DIR_BIT_SHIFT) | \
368b3a89faSSona Mathew ((substream && SUBSTREAM_MASK) << SUBSTREAM_SHIFT) | \
378b3a89faSSona Mathew ((stream_id && STREAM_ID_MASK) << STREAM_ID_SHIFT))
388b3a89faSSona Mathew
398c980a4aSJavier Almansa Sobrino /* Parameters received from the previous image */
408c980a4aSJavier Almansa Sobrino static unsigned int trp_boot_abi_version;
418c980a4aSJavier Almansa Sobrino static uintptr_t trp_shared_region_start;
428c980a4aSJavier Almansa Sobrino
431d0ca40eSJavier Almansa Sobrino /* Parameters received from boot manifest */
441d0ca40eSJavier Almansa Sobrino uint32_t trp_boot_manifest_version;
458c980a4aSJavier Almansa Sobrino
4650a3056aSZelalem Aweke /*******************************************************************************
4750a3056aSZelalem Aweke * Setup function for TRP.
4850a3056aSZelalem Aweke ******************************************************************************/
trp_setup(uint64_t x0,uint64_t x1,uint64_t x2,uint64_t x3)498c980a4aSJavier Almansa Sobrino void trp_setup(uint64_t x0,
508c980a4aSJavier Almansa Sobrino uint64_t x1,
518c980a4aSJavier Almansa Sobrino uint64_t x2,
528c980a4aSJavier Almansa Sobrino uint64_t x3)
5350a3056aSZelalem Aweke {
548c980a4aSJavier Almansa Sobrino /*
55b96253dbSAlexeiFedorov * Validate boot parameters
568c980a4aSJavier Almansa Sobrino *
57b96253dbSAlexeiFedorov * According to the Boot Interface ABI v.0.1,
58b96253dbSAlexeiFedorov * the parameters received from EL3 are:
59b96253dbSAlexeiFedorov * x0: CPUID (verified earlier, so not used)
608c980a4aSJavier Almansa Sobrino * x1: Boot Interface version
618c980a4aSJavier Almansa Sobrino * x2: PLATFORM_CORE_COUNT
628c980a4aSJavier Almansa Sobrino * x3: Pointer to the shared memory area.
638c980a4aSJavier Almansa Sobrino */
648c980a4aSJavier Almansa Sobrino
658c980a4aSJavier Almansa Sobrino (void)x0;
668c980a4aSJavier Almansa Sobrino
678c980a4aSJavier Almansa Sobrino if (TRP_RMM_EL3_VERSION_GET_MAJOR(x1) != TRP_RMM_EL3_ABI_VERS_MAJOR) {
688c980a4aSJavier Almansa Sobrino trp_boot_abort(E_RMM_BOOT_VERSION_MISMATCH);
698c980a4aSJavier Almansa Sobrino }
708c980a4aSJavier Almansa Sobrino
718c980a4aSJavier Almansa Sobrino if ((void *)x3 == NULL) {
728c980a4aSJavier Almansa Sobrino trp_boot_abort(E_RMM_BOOT_INVALID_SHARED_BUFFER);
738c980a4aSJavier Almansa Sobrino }
748c980a4aSJavier Almansa Sobrino
758c980a4aSJavier Almansa Sobrino if (x2 > TRP_PLATFORM_CORE_COUNT) {
768c980a4aSJavier Almansa Sobrino trp_boot_abort(E_RMM_BOOT_CPUS_OUT_OF_RANGE);
778c980a4aSJavier Almansa Sobrino }
788c980a4aSJavier Almansa Sobrino
798c980a4aSJavier Almansa Sobrino trp_boot_abi_version = x1;
808c980a4aSJavier Almansa Sobrino trp_shared_region_start = x3;
818c980a4aSJavier Almansa Sobrino flush_dcache_range((uintptr_t)&trp_boot_abi_version,
828c980a4aSJavier Almansa Sobrino sizeof(trp_boot_abi_version));
838c980a4aSJavier Almansa Sobrino flush_dcache_range((uintptr_t)&trp_shared_region_start,
848c980a4aSJavier Almansa Sobrino sizeof(trp_shared_region_start));
858c980a4aSJavier Almansa Sobrino
8650a3056aSZelalem Aweke /* Perform early platform-specific setup */
87a97bfa5fSAlexeiFedorov trp_early_platform_setup((struct rmm_manifest *)trp_shared_region_start);
8850a3056aSZelalem Aweke }
8950a3056aSZelalem Aweke
trp_validate_warmboot_args(uint64_t x0,uint64_t x1,uint64_t x2,uint64_t x3)90dc0ca64eSJavier Almansa Sobrino int trp_validate_warmboot_args(uint64_t x0, uint64_t x1,
91dc0ca64eSJavier Almansa Sobrino uint64_t x2, uint64_t x3)
92dc0ca64eSJavier Almansa Sobrino {
93dc0ca64eSJavier Almansa Sobrino /*
94dc0ca64eSJavier Almansa Sobrino * Validate boot parameters for warm boot
95dc0ca64eSJavier Almansa Sobrino *
96dc0ca64eSJavier Almansa Sobrino * According to the Boot Interface ABI v.0.1, the parameters
97dc0ca64eSJavier Almansa Sobrino * received from EL3 during warm boot are:
98dc0ca64eSJavier Almansa Sobrino *
99dc0ca64eSJavier Almansa Sobrino * x0: CPUID (verified earlier so not used here)
10089d979ceSAndre Przywara * x1: activation token (ignored)
10189d979ceSAndre Przywara * [x2:x3]: RES0
102dc0ca64eSJavier Almansa Sobrino */
103dc0ca64eSJavier Almansa Sobrino
104dc0ca64eSJavier Almansa Sobrino (void)x0;
10589d979ceSAndre Przywara (void)x1;
106dc0ca64eSJavier Almansa Sobrino
107*ab5db334SAndre Przywara if ((x2 | x3) != 0UL) {
108*ab5db334SAndre Przywara ERROR("TRP: extra warmboot arguments not 0: x2=0x%lx, x3=0x%lx\n",
109*ab5db334SAndre Przywara x2, x3);
110*ab5db334SAndre Przywara return E_RMM_BOOT_UNKNOWN;
111*ab5db334SAndre Przywara }
112*ab5db334SAndre Przywara
113*ab5db334SAndre Przywara return 0;
114dc0ca64eSJavier Almansa Sobrino }
115dc0ca64eSJavier Almansa Sobrino
11650a3056aSZelalem Aweke /* Main function for TRP */
trp_main(void)11750a3056aSZelalem Aweke void trp_main(void)
11850a3056aSZelalem Aweke {
119758ccb80SChris Kay NOTICE("TRP: %s\n", build_version_string);
12050a3056aSZelalem Aweke NOTICE("TRP: %s\n", build_message);
1218c980a4aSJavier Almansa Sobrino NOTICE("TRP: Supported RMM-EL3 Interface ABI: v.%u.%u\n",
1228c980a4aSJavier Almansa Sobrino TRP_RMM_EL3_ABI_VERS_MAJOR, TRP_RMM_EL3_ABI_VERS_MINOR);
1231d0ca40eSJavier Almansa Sobrino NOTICE("TRP: Boot Manifest Version: v.%u.%u\n",
1241d0ca40eSJavier Almansa Sobrino RMMD_GET_MANIFEST_VERSION_MAJOR(trp_boot_manifest_version),
1251d0ca40eSJavier Almansa Sobrino RMMD_GET_MANIFEST_VERSION_MINOR(trp_boot_manifest_version));
12650a3056aSZelalem Aweke INFO("TRP: Memory base: 0x%lx\n", (unsigned long)RMM_BASE);
127b96253dbSAlexeiFedorov INFO("TRP: Shared region base address: 0x%lx\n",
1288c980a4aSJavier Almansa Sobrino (unsigned long)trp_shared_region_start);
129b96253dbSAlexeiFedorov INFO("TRP: Total size: 0x%lx bytes\n",
130b96253dbSAlexeiFedorov (unsigned long)(RMM_END - RMM_BASE));
1318c980a4aSJavier Almansa Sobrino INFO("TRP: RMM-EL3 Interface ABI reported by EL3: v.%u.%u\n",
1328c980a4aSJavier Almansa Sobrino TRP_RMM_EL3_VERSION_GET_MAJOR(trp_boot_abi_version),
1338c980a4aSJavier Almansa Sobrino TRP_RMM_EL3_VERSION_GET_MINOR(trp_boot_abi_version));
13450a3056aSZelalem Aweke }
13550a3056aSZelalem Aweke
13650a3056aSZelalem Aweke /*******************************************************************************
13750a3056aSZelalem Aweke * Returning RMI version back to Normal World
13850a3056aSZelalem Aweke ******************************************************************************/
trp_ret_rmi_version(unsigned long long rmi_version,struct trp_smc_result * smc_ret)139ade6000fSShruti Gupta static void trp_ret_rmi_version(unsigned long long rmi_version,
140ade6000fSShruti Gupta struct trp_smc_result *smc_ret)
14150a3056aSZelalem Aweke {
142ade6000fSShruti Gupta if (rmi_version != RMI_ABI_VERSION) {
143ade6000fSShruti Gupta smc_ret->x[0] = RMI_ERROR_INPUT;
144ade6000fSShruti Gupta } else {
145ade6000fSShruti Gupta smc_ret->x[0] = RMI_SUCCESS;
146ade6000fSShruti Gupta }
14750a3056aSZelalem Aweke VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR,
14850a3056aSZelalem Aweke RMI_ABI_VERSION_MINOR);
149ade6000fSShruti Gupta smc_ret->x[1] = RMI_ABI_VERSION;
150ade6000fSShruti Gupta smc_ret->x[2] = RMI_ABI_VERSION;
15150a3056aSZelalem Aweke }
15250a3056aSZelalem Aweke
15350a3056aSZelalem Aweke /*******************************************************************************
15450a3056aSZelalem Aweke * Transitioning granule of NON-SECURE type to REALM type
15550a3056aSZelalem Aweke ******************************************************************************/
trp_asc_mark_realm(unsigned long long x1,struct trp_smc_result * smc_ret)156b96253dbSAlexeiFedorov static void trp_asc_mark_realm(unsigned long long x1,
157b96253dbSAlexeiFedorov struct trp_smc_result *smc_ret)
15850a3056aSZelalem Aweke {
15950a3056aSZelalem Aweke VERBOSE("Delegating granule 0x%llx\n", x1);
160b96253dbSAlexeiFedorov smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_DELEGATE, x1,
1618b3a89faSSona Mathew 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
16250a3056aSZelalem Aweke
163b96253dbSAlexeiFedorov if (smc_ret->x[0] != 0ULL) {
16450a3056aSZelalem Aweke ERROR("Granule transition from NON-SECURE type to REALM type "
165b96253dbSAlexeiFedorov "failed 0x%llx\n", smc_ret->x[0]);
16650a3056aSZelalem Aweke }
16750a3056aSZelalem Aweke }
16850a3056aSZelalem Aweke
16950a3056aSZelalem Aweke /*******************************************************************************
17050a3056aSZelalem Aweke * Transitioning granule of REALM type to NON-SECURE type
17150a3056aSZelalem Aweke ******************************************************************************/
trp_asc_mark_nonsecure(unsigned long long x1,struct trp_smc_result * smc_ret)172b96253dbSAlexeiFedorov static void trp_asc_mark_nonsecure(unsigned long long x1,
173b96253dbSAlexeiFedorov struct trp_smc_result *smc_ret)
17450a3056aSZelalem Aweke {
17550a3056aSZelalem Aweke VERBOSE("Undelegating granule 0x%llx\n", x1);
176b96253dbSAlexeiFedorov smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_UNDELEGATE, x1,
1778b3a89faSSona Mathew 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
17850a3056aSZelalem Aweke
179b96253dbSAlexeiFedorov if (smc_ret->x[0] != 0ULL) {
18050a3056aSZelalem Aweke ERROR("Granule transition from REALM type to NON-SECURE type "
181b96253dbSAlexeiFedorov "failed 0x%llx\n", smc_ret->x[0]);
18250a3056aSZelalem Aweke }
18350a3056aSZelalem Aweke }
18450a3056aSZelalem Aweke
18550a3056aSZelalem Aweke /*******************************************************************************
1868b3a89faSSona Mathew * Test the IDE Key management interface
1878b3a89faSSona Mathew ******************************************************************************/
trp_ide_keymgmt_interface_fn(unsigned long long x1,unsigned long long x2,struct trp_smc_result * smc_ret)1888b3a89faSSona Mathew static void trp_ide_keymgmt_interface_fn(unsigned long long x1, unsigned long long x2,
1898b3a89faSSona Mathew struct trp_smc_result *smc_ret)
1908b3a89faSSona Mathew {
1918b3a89faSSona Mathew uint64_t ecam_address = 0U, rp_id = 0U, ide_stream_info;
1928b3a89faSSona Mathew uint64_t keyqw0, keyqw1, keyqw2, keyqw3;
1938b3a89faSSona Mathew uint64_t ifvqw0, ifvqw1;
1948b3a89faSSona Mathew int return_value;
1958b3a89faSSona Mathew
1968b3a89faSSona Mathew #if RMMD_ENABLE_IDE_KEY_PROG
1978b3a89faSSona Mathew trp_get_test_rootport(&ecam_address, &rp_id);
1988b3a89faSSona Mathew #endif /* RMMD_ENABLE_IDE_KEY_PROG */
1998b3a89faSSona Mathew /*
2008b3a89faSSona Mathew * Dummy values for testing:
2018b3a89faSSona Mathew * Key set = 0x0
2028b3a89faSSona Mathew * Dir = 0x0
2038b3a89faSSona Mathew * Substream = 0x1
2048b3a89faSSona Mathew * Stream ID = 0x1
2058b3a89faSSona Mathew */
2068b3a89faSSona Mathew ide_stream_info = ENCODE_STREAM_INFO(KEY_SET, DIR_VAL, SUBSTREAM_VAL, STREAM_ID);
2078b3a89faSSona Mathew
2088b3a89faSSona Mathew /* Dummy key and IV values for testing */
2098b3a89faSSona Mathew keyqw0 = 0xA1B2C3D4E5F60708;
2108b3a89faSSona Mathew keyqw1 = 0x1122334455667788;
2118b3a89faSSona Mathew keyqw2 = 0xDEADBEEFCAFEBABE;
2128b3a89faSSona Mathew keyqw3 = 0x1234567890ABCDEF;
2138b3a89faSSona Mathew ifvqw0 = 0xABCDEF0123456789;
2148b3a89faSSona Mathew ifvqw1 = 0x9876543210FEDCBA;
2158b3a89faSSona Mathew
2168b3a89faSSona Mathew return_value = trp_smc(set_smc_args(RMM_IDE_KEY_PROG, ecam_address, rp_id,
2178b3a89faSSona Mathew ide_stream_info, keyqw0, keyqw1, keyqw2, keyqw3, ifvqw0,
2188b3a89faSSona Mathew ifvqw1, 0UL, 0UL));
2198b3a89faSSona Mathew
2208b3a89faSSona Mathew INFO("return value from RMM_IDE_KEY_PROG = %d\n", return_value);
2218b3a89faSSona Mathew
2228b3a89faSSona Mathew return_value = trp_smc(set_smc_args(RMM_IDE_KEY_SET_GO, ecam_address, rp_id,
2238b3a89faSSona Mathew ide_stream_info, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
2248b3a89faSSona Mathew
2258b3a89faSSona Mathew INFO("return value from RMM_IDE_KEY_SET_GO = %d\n", return_value);
2268b3a89faSSona Mathew
2278b3a89faSSona Mathew return_value = trp_smc(set_smc_args(RMM_IDE_KEY_SET_STOP, ecam_address, rp_id,
2288b3a89faSSona Mathew ide_stream_info, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
2298b3a89faSSona Mathew
2308b3a89faSSona Mathew INFO("return value from RMM_IDE_KEY_SET_STOP = %d\n", return_value);
2318b3a89faSSona Mathew
2328b3a89faSSona Mathew return_value = trp_smc(set_smc_args(RMM_IDE_KM_PULL_RESPONSE, ecam_address, rp_id,
2338b3a89faSSona Mathew 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
2348b3a89faSSona Mathew
2358b3a89faSSona Mathew INFO("return value from RMM_IDE_KEY_SET_STOP = %d\n", return_value);
2368b3a89faSSona Mathew
2378b3a89faSSona Mathew smc_ret->x[0] = RMI_ERROR_NOT_SUPPORTED;
2388b3a89faSSona Mathew
2398b3a89faSSona Mathew }
2408b3a89faSSona Mathew
2418b3a89faSSona Mathew /*******************************************************************************
24250a3056aSZelalem Aweke * Main RMI SMC handler function
24350a3056aSZelalem Aweke ******************************************************************************/
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)244b96253dbSAlexeiFedorov void trp_rmi_handler(unsigned long fid,
245b96253dbSAlexeiFedorov unsigned long long x1, unsigned long long x2,
246b96253dbSAlexeiFedorov unsigned long long x3, unsigned long long x4,
247b96253dbSAlexeiFedorov unsigned long long x5, unsigned long long x6,
248b96253dbSAlexeiFedorov struct trp_smc_result *smc_ret)
24950a3056aSZelalem Aweke {
250b96253dbSAlexeiFedorov /* Not used in the current implementation */
251b96253dbSAlexeiFedorov (void)x2;
252b96253dbSAlexeiFedorov (void)x3;
253b96253dbSAlexeiFedorov (void)x4;
254b96253dbSAlexeiFedorov (void)x5;
255b96253dbSAlexeiFedorov (void)x6;
256b96253dbSAlexeiFedorov
25750a3056aSZelalem Aweke switch (fid) {
25850a3056aSZelalem Aweke case RMI_RMM_REQ_VERSION:
259ade6000fSShruti Gupta trp_ret_rmi_version(x1, smc_ret);
260b96253dbSAlexeiFedorov break;
26150a3056aSZelalem Aweke case RMI_RMM_GRANULE_DELEGATE:
262b96253dbSAlexeiFedorov trp_asc_mark_realm(x1, smc_ret);
263b96253dbSAlexeiFedorov break;
26450a3056aSZelalem Aweke case RMI_RMM_GRANULE_UNDELEGATE:
265b96253dbSAlexeiFedorov trp_asc_mark_nonsecure(x1, smc_ret);
266b96253dbSAlexeiFedorov break;
2678b3a89faSSona Mathew case RMI_RMM_PDEV_CREATE:
2688b3a89faSSona Mathew trp_ide_keymgmt_interface_fn(x1, x2, smc_ret);
2698b3a89faSSona Mathew break;
27050a3056aSZelalem Aweke default:
271b96253dbSAlexeiFedorov ERROR("Invalid SMC code to %s, FID %lx\n", __func__, fid);
272b96253dbSAlexeiFedorov smc_ret->x[0] = SMC_UNK;
27350a3056aSZelalem Aweke }
27450a3056aSZelalem Aweke }
275