feat(rmmd): el3-rmm ide key management interface

Patch introduces the EL3-RMM SMC Interface for Root Port
Key management as per RFC discussed here:
https://github.com/TF-RMM/tf-rmm/wiki/RFC:-EL3-RMM-IDE-KM-Interface

Three IDE Key management smc calls have been added:
 - RMM_IDE_KEY_PROG()
 - RMM_IDE_KEY_SET_GO()
 - RMM_IDE_KEY_SET_STOP()
 - RMM_IDE_KM_PULL_RESPONSE()

Due to the absence of root port support in FVP, we are
currently adding placeholders in this patch for the platform
APIs to return success irrespective of the arguments being passed
by the caller(Realms). The SMCs are guarded by
`RMMD_ENABLE_IDE_KEY_PROG` build flag and is disabled by default.
We expect that once the SMCs are stabilized, this build flag will
not be required anymore.

Change-Id: I9411eb7787dac2a207bd14710d251503bd9626ce
Signed-off-by: Sona Mathew <sonarebecca.mathew@arm.com>
diff --git a/Makefile b/Makefile
index aae3452..ecd9bcf 100644
--- a/Makefile
+++ b/Makefile
@@ -1239,6 +1239,7 @@
 	DISCRETE_TPM \
 	DICE_PROTECTION_ENVIRONMENT \
 	RMMD_ENABLE_EL3_TOKEN_SIGN \
+	RMMD_ENABLE_IDE_KEY_PROG \
 	DRTM_SUPPORT \
 	NS_TIMER_SWITCH \
 	OVERRIDE_LIBC \
@@ -1405,6 +1406,7 @@
 	ENABLE_PSCI_STAT \
 	ENABLE_RME \
 	RMMD_ENABLE_EL3_TOKEN_SIGN \
+	RMMD_ENABLE_IDE_KEY_PROG \
 	ENABLE_RUNTIME_INSTRUMENTATION \
 	ENABLE_SME_FOR_NS \
 	ENABLE_SME2_FOR_NS \
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index e10770c..b9985a3 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -399,6 +399,24 @@
 size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared);
 int plat_rmmd_load_manifest(struct rmm_manifest *manifest);
 int plat_rmmd_mecid_key_update(uint16_t mecid);
+
+/* The following 4 functions are to be implemented if
+ * RMMD_ENABLE_IDE_KEY_PROG=1.
+ * The following functions are expected to return E_RMM_* error codes.
+ */
+int plat_rmmd_el3_ide_key_program(uint64_t ecam_address, uint64_t root_port_id,
+				  uint64_t ide_stream_info,
+				  rp_ide_key_info_t *ide_key_info_ptr,
+				  uint64_t request_id, uint64_t cookie);
+int plat_rmmd_el3_ide_key_set_go(uint64_t ecam_address, uint64_t root_port_id,
+				 uint64_t ide_stream_info, uint64_t request_id,
+				 uint64_t cookie);
+int plat_rmmd_el3_ide_key_set_stop(uint64_t ecam_address, uint64_t root_port_id,
+				   uint64_t ide_stream_info, uint64_t request_id,
+				   uint64_t cookie);
+int plat_rmmd_el3_ide_km_pull_response(uint64_t ecam_address, uint64_t root_port_id,
+				   uint64_t *req_resp, uint64_t *request_id,
+				   uint64_t *cookie);
 #endif /* ENABLE_RME */
 
 /*******************************************************************************
diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h
index 8bf9319..9b99e92 100644
--- a/include/services/rmmd_svc.h
+++ b/include/services/rmmd_svc.h
@@ -92,6 +92,8 @@
 #define E_RMM_NOMEM			-4
 #define E_RMM_INVAL			-5
 #define E_RMM_AGAIN			-6
+#define E_RMM_FAULT			-7
+#define E_RMM_IN_PROGRESS		-8
 
 /* Return error codes from RMI SMCs */
 #define RMI_SUCCESS			0
@@ -179,6 +181,83 @@
 /* Identifier for the hash algorithm used for attestation signing */
 #define EL3_TOKEN_SIGN_HASH_ALG_SHA384		U(1)
 
+/* Starting RMM-EL3 interface version 0.6 */
+/*
+ * Function codes to support RMM IDE Key management Interface.
+ * The arguments to this SMC are:
+ *     arg0 - Function ID.
+ *     arg1 - Enhanced Configuration Access Mechanism address
+ *     arg2 - Root Port ID
+ *     arg3 - IDE selective stream info
+ *     arg4 - Quad word of key[63:0]
+ *     arg5 - Quad word of key[127:64]
+ *     arg6 - Quad word of key[191:128]
+ *     arg7 - Quad word of key[255:192]
+ *     arg8 - Quad word of IV [63:0]
+ *     arg9 - Quad word of IV [95:64]
+ *     arg10 - request_id
+ *     arg11 - cookie
+ * The return arguments are:
+ *     ret0 - Status/Error
+ */
+#define RMM_IDE_KEY_PROG			SMC64_RMMD_EL3_FID(U(7))
+
+/*******************************************************************************
+ * Structure to hold el3_ide_key info
+ ******************************************************************************/
+#ifndef __ASSEMBLER__
+typedef struct rp_ide_key_info {
+	uint64_t keyqw0;
+	uint64_t keyqw1;
+	uint64_t keyqw2;
+	uint64_t keyqw3;
+	uint64_t ifvqw0;
+	uint64_t ifvqw1;
+} rp_ide_key_info_t;
+#endif /* __ASSEMBLER__ */
+
+/*
+ * Function codes to support RMM IDE Key management Interface.
+ * The arguments to this SMC are:
+ *     arg0 - Function ID.
+ *     arg1 - Enhanced Configuration Access Mechanism address
+ *     arg2 - Root Port ID
+ *     arg3 - IDE selective stream info
+ *     arg4 - request_id
+ *     arg5 - cookie
+ * The return arguments are:
+ *     ret0 - Status/Error
+ */
+#define RMM_IDE_KEY_SET_GO			SMC64_RMMD_EL3_FID(U(8))
+
+/*
+ * Function codes to support RMM IDE Key management Interface.
+ * The arguments to this SMC are:
+ *     arg0 - Function ID.
+ *     arg1 - Enhanced Configuration Access Mechanism address
+ *     arg2 - Root Port ID
+ *     arg3 - IDE selective stream info
+ *     arg4 - request_id
+ *     arg5 - cookie
+ * The return arguments are:
+ *     ret0 - Status/Error
+ */
+#define RMM_IDE_KEY_SET_STOP			SMC64_RMMD_EL3_FID(U(9))
+
+/*
+ * Function codes to support RMM IDE Key management Interface.
+ * The arguments to this SMC are:
+ *     arg0 - Function ID.
+ *     arg1 - Enhanced Configuration Access Mechanism address
+ *     arg2 - Root Port ID
+ * The return arguments are:
+ *     ret0 - Status/Error
+ *     ret1 - Retrieved response corresponding to the previous request.
+ *     ret2 - request_id
+ *     ret3 - cookie
+ */
+#define RMM_IDE_KM_PULL_RESPONSE		SMC64_RMMD_EL3_FID(U(10))
+
 /*
  * RMM_BOOT_COMPLETE originates on RMM when the boot finishes (either cold
  * or warm boot). This is handled by the RMM-EL3 interface SMC handler.
@@ -200,7 +279,7 @@
  * Increase this when a bug is fixed, or a feature is added without
  * breaking compatibility.
  */
-#define RMM_EL3_IFC_VERSION_MINOR	(U(5))
+#define RMM_EL3_IFC_VERSION_MINOR	(U(6))
 
 #define RMM_EL3_INTERFACE_VERSION				\
 	(((RMM_EL3_IFC_VERSION_MAJOR << 16) & 0x7FFFF) |	\
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 906e5d7..965698b 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -432,3 +432,8 @@
 
 # Enable RMMD to forward attestation requests from RMM to EL3.
 RMMD_ENABLE_EL3_TOKEN_SIGN	:= 0
+
+# Enable RMMD to program and manage IDE Keys at the PCIe Root Port(RP).
+# This flag is temporary and it is expected once the interface is
+# finalized, this flag will be removed.
+RMMD_ENABLE_IDE_KEY_PROG	:= 0
diff --git a/plat/arm/board/fvp/fvp_ide_keymgmt.c b/plat/arm/board/fvp/fvp_ide_keymgmt.c
new file mode 100644
index 0000000..53ed433
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_ide_keymgmt.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <plat/common/platform.h>
+
+int plat_rmmd_el3_ide_key_program(uint64_t ecam_address, uint64_t root_port_id,
+				  uint64_t ide_stream_info,
+				  rp_ide_key_info_t *ide_key_info_ptr, uint64_t request_id,
+				  uint64_t cookie)
+{
+	/* placeholder to add further implementation */
+
+	return 0;
+
+}
+
+int plat_rmmd_el3_ide_key_set_go(uint64_t ecam_address, uint64_t root_port_id,
+				 uint64_t ide_stream_info, uint64_t request_id,
+				 uint64_t cookie)
+{
+	/* placeholder to add further implementation */
+
+	return 0;
+
+}
+
+int plat_rmmd_el3_ide_key_set_stop(uint64_t ecam_address, uint64_t root_port_id,
+				   uint64_t ide_stream_info, uint64_t request_id,
+				   uint64_t cookie)
+{
+	/* placeholder to add further implementation */
+
+	return 0;
+}
+
+int plat_rmmd_el3_ide_km_pull_response(uint64_t ecam_address, uint64_t root_port_id,
+				   uint64_t *req_resp, uint64_t *request,
+				   uint64_t *cookie)
+{
+	/* placeholder to add further implementation */
+
+	return E_RMM_UNK;
+}
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 8c114e7..280aa39 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -95,6 +95,7 @@
 
 ifeq (${ENABLE_RME},1)
     ENABLE_FEAT_MEC		:= 2
+    RMMD_ENABLE_IDE_KEY_PROG	:= 1
 endif
 
 # The FVP platform depends on this macro to build with correct GIC driver.
@@ -302,7 +303,8 @@
 
 BL31_SOURCES		+=	plat/arm/board/fvp/fvp_plat_attest_token.c	\
 				plat/arm/board/fvp/fvp_realm_attest_key.c	\
-				plat/arm/board/fvp/fvp_el3_token_sign.c
+				plat/arm/board/fvp/fvp_el3_token_sign.c		\
+				plat/arm/board/fvp/fvp_ide_keymgmt.c
 endif
 
 ifeq (${ENABLE_FEAT_RNG_TRAP},1)
diff --git a/services/std_svc/rmmd/rmmd.mk b/services/std_svc/rmmd/rmmd.mk
index eae5031..67955ff 100644
--- a/services/std_svc/rmmd/rmmd.mk
+++ b/services/std_svc/rmmd/rmmd.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021-2024, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2025, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -16,7 +16,8 @@
 RMMD_SOURCES	+=	$(addprefix services/std_svc/rmmd/,	\
 			${ARCH}/rmmd_helpers.S			\
 			rmmd_main.c				\
-			rmmd_attest.c)
+			rmmd_attest.c				\
+			rmmd_keymgmt.c)
 
 # Let the top-level Makefile know that we intend to include RMM image
 NEED_RMM	:=	yes
diff --git a/services/std_svc/rmmd/rmmd_keymgmt.c b/services/std_svc/rmmd/rmmd_keymgmt.c
new file mode 100644
index 0000000..2414b35
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_keymgmt.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include "rmmd_private.h"
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <services/rmmd_svc.h>
+#include <smccc_helpers.h>
+
+#define DIR_BIT_SHIFT		0xB
+#define KEYSET_BIT_SHIFT	0xC
+#define STREAM_ID_MASK		0xFF
+#define SUBSTREAM_MASK		0x7
+#define SUBSTREAM_SHIFT		0x8
+#define MAX_STREAM_ID		32U
+#define MAX_SUBSTREAM		3U
+
+bool extract_ide_stream_info(uint64_t ide_stream_info)
+{
+	uint8_t keyset, dir;
+	uint8_t stream_id, substream;
+
+	/* Extract keyset, dir, substream and stream ID */
+	keyset = (ide_stream_info >> KEYSET_BIT_SHIFT) & 0x1;
+	dir = (ide_stream_info >> DIR_BIT_SHIFT) & 0x1;
+	stream_id = ide_stream_info & STREAM_ID_MASK;
+	substream = (ide_stream_info >> SUBSTREAM_SHIFT) & SUBSTREAM_MASK;
+
+	if ((stream_id >= MAX_STREAM_ID) || (substream >= MAX_SUBSTREAM)) {
+		ERROR("invalid input: stream_id = %x, substream = %x\n", stream_id, substream);
+		return false;
+	}
+
+	VERBOSE("keyset = %d, dir = %d, stream_id = %d and substream = %d\n", keyset, dir,
+		 stream_id, substream);
+
+	return true;
+}
+
+int rmmd_el3_ide_key_program(uint64_t ecam_address, uint64_t rp_id,
+			     uint64_t ide_stream_info, rp_ide_key_info_t *ide_key_info_ptr,
+			     uint64_t request_id, uint64_t cookie)
+{
+	int err;
+
+	/* TODO: Do validation of params */
+
+	VERBOSE("IDE_KEY_PROG: ecam address = 0x%lx and rp_id = 0x%lx\n", ecam_address, rp_id);
+
+	if (!extract_ide_stream_info(ide_stream_info)) {
+		err = E_RMM_INVAL;
+		goto exit_fn;
+	}
+
+	err = plat_rmmd_el3_ide_key_program(ecam_address, rp_id, ide_stream_info,
+					    ide_key_info_ptr, request_id, cookie);
+
+	assert(err == E_RMM_OK || err == E_RMM_AGAIN || err == E_RMM_INVAL ||
+		err == E_RMM_IN_PROGRESS || err == E_RMM_UNK || err == E_RMM_FAULT);
+
+exit_fn:
+	return err;
+}
+
+int rmmd_el3_ide_key_set_go(uint64_t ecam_address, uint64_t rp_id,
+			    uint64_t ide_stream_info, uint64_t request_id,
+			    uint64_t cookie)
+{
+	int err;
+
+	/* TODO: Do validation of params */
+
+	VERBOSE("IDE_KEY_SET_GO: ecam address = 0x%lx and rp_id = 0x%lx\n", ecam_address, rp_id);
+
+	if (!extract_ide_stream_info(ide_stream_info)) {
+		err = E_RMM_INVAL;
+		goto exit_fn;
+	}
+
+	err = plat_rmmd_el3_ide_key_set_go(ecam_address, rp_id, ide_stream_info,
+					   request_id, cookie);
+
+	assert(err == E_RMM_OK || err == E_RMM_AGAIN || err == E_RMM_INVAL ||
+		err == E_RMM_IN_PROGRESS || err == E_RMM_UNK || err == E_RMM_FAULT);
+
+exit_fn:
+	return err;
+}
+
+int rmmd_el3_ide_key_set_stop(uint64_t ecam_address, uint64_t rp_id,
+			      uint64_t ide_stream_info, uint64_t request_id,
+			      uint64_t cookie)
+{
+	int err;
+
+	/* TODO: Do validation of params */
+
+	VERBOSE("IDE_KEY_SET_STOP: ecam address = 0x%lx and rp_id = 0x%lx\n", ecam_address, rp_id);
+
+	if (!extract_ide_stream_info(ide_stream_info)) {
+		err = E_RMM_INVAL;
+		goto exit_fn;
+	}
+
+	err = plat_rmmd_el3_ide_key_set_stop(ecam_address, rp_id, ide_stream_info,
+					     request_id, cookie);
+
+	assert(err == E_RMM_OK || err == E_RMM_AGAIN || err == E_RMM_INVAL ||
+		err == E_RMM_IN_PROGRESS || err == E_RMM_UNK || err == E_RMM_FAULT);
+
+exit_fn:
+	return err;
+}
+
+int rmmd_el3_ide_km_pull_response(uint64_t ecam_address, uint64_t rp_id,
+				  uint64_t *req_resp, uint64_t *request_id,
+				  uint64_t *cookie)
+{
+	int err;
+
+	/* TODO: Do validation of params */
+
+	VERBOSE("IDE_KM_PULL: ecam address = 0x%lx, rp_id = 0x%lx\n", ecam_address, rp_id);
+
+	err = plat_rmmd_el3_ide_km_pull_response(ecam_address, rp_id, req_resp, request_id, cookie);
+
+	assert(err == E_RMM_OK || err == E_RMM_AGAIN || err == E_RMM_INVAL ||
+		err == E_RMM_IN_PROGRESS || err == E_RMM_UNK || err == E_RMM_FAULT);
+
+	return err;
+}
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index 19c8373..35582dc 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -561,6 +561,37 @@
 	case RMM_EL3_TOKEN_SIGN:
 		return rmmd_el3_token_sign(handle, x1, x2, x3, x4);
 #endif
+
+#if RMMD_ENABLE_IDE_KEY_PROG
+	case RMM_IDE_KEY_PROG:
+	{
+		rp_ide_key_info_t ide_key_info;
+
+		ide_key_info.keyqw0 = x4;
+		ide_key_info.keyqw1 = SMC_GET_GP(handle, CTX_GPREG_X5);
+		ide_key_info.keyqw2 = SMC_GET_GP(handle, CTX_GPREG_X6);
+		ide_key_info.keyqw3 = SMC_GET_GP(handle, CTX_GPREG_X7);
+		ide_key_info.ifvqw0 = SMC_GET_GP(handle, CTX_GPREG_X8);
+		ide_key_info.ifvqw1 = SMC_GET_GP(handle, CTX_GPREG_X9);
+		uint64_t x10 = SMC_GET_GP(handle, CTX_GPREG_X10);
+		uint64_t x11 = SMC_GET_GP(handle, CTX_GPREG_X11);
+
+		ret = rmmd_el3_ide_key_program(x1, x2, x3, &ide_key_info, x10, x11);
+		SMC_RET1(handle, ret);
+	}
+	case RMM_IDE_KEY_SET_GO:
+		ret = rmmd_el3_ide_key_set_go(x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5));
+		SMC_RET1(handle, ret);
+	case RMM_IDE_KEY_SET_STOP:
+		ret = rmmd_el3_ide_key_set_stop(x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5));
+		SMC_RET1(handle, ret);
+	case RMM_IDE_KM_PULL_RESPONSE: {
+		uint64_t req_resp = 0, req_id = 0, cookie_var = 0;
+
+		ret = rmmd_el3_ide_km_pull_response(x1, x2, &req_resp, &req_id, &cookie_var);
+		SMC_RET4(handle, ret, req_resp, req_id, cookie_var);
+	}
+#endif /* RMMD_ENABLE_IDE_KEY_PROG */
 	case RMM_BOOT_COMPLETE:
 		VERBOSE("RMMD: running rmmd_rmm_sync_exit\n");
 		rmmd_rmm_sync_exit(x1);
diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h
index 0ce104d..1fbcd31 100644
--- a/services/std_svc/rmmd/rmmd_private.h
+++ b/services/std_svc/rmmd/rmmd_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,7 @@
 #define RMMD_PRIVATE_H
 
 #include <context.h>
+#include <services/rmmd_svc.h>
 
 /*******************************************************************************
  * Constants that allow assembler code to preserve callee-saved registers of the
@@ -54,6 +55,17 @@
 uint64_t rmmd_el3_token_sign(void *handle, uint64_t x1, uint64_t x2,
 				    uint64_t x3, uint64_t x4);
 
+/* Functions implementing IDE KM programming */
+int rmmd_el3_ide_key_program(uint64_t ecam_address, uint64_t rp_id,
+			     uint64_t ide_stream_info, rp_ide_key_info_t *ide_key_info_ptr,
+			     uint64_t request_id, uint64_t cookie);
+int rmmd_el3_ide_key_set_go(uint64_t ecam_address, uint64_t rp_id, uint64_t ide_stream_info,
+			    uint64_t request_id, uint64_t cookie);
+int rmmd_el3_ide_key_set_stop(uint64_t ecam_address, uint64_t rp_id, uint64_t ide_stream_info,
+			      uint64_t request_id, uint64_t cookie);
+int rmmd_el3_ide_km_pull_response(uint64_t ecam_address, uint64_t rp_id, uint64_t *req_resp,
+				  uint64_t *request_id, uint64_t *cookie_ptr);
+
 /* Assembly helpers */
 uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);
 void __dead2 rmmd_rmm_exit(uint64_t c_rt_ctx, uint64_t ret);