feat(realm): added support to invoke RSI RDEV ABIs

- Updated DA RSI data types with RMM spec 1.1-alp11.1.
- Added support to call DA RSI RDEV ABIs like
  SMC_RSI_RDEV_CONTINUE
  SMC_RSI_RDEV_STOP
  SMC_RSI_RDEV_START
  SMC_RSI_RDEV_GET_INTERFACE_REPORT
  SMC_RSI_RDEV_LOCK
  SMC_RSI_RDEV_GET_INFO
  SMC_RSI_RDEV_GET_MEASUREMENTS
  SMC_RSI_RDEV_GET_STATE
  SMC_RSI_RDEV_GET_INSTANCE_ID

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I60664262c24f287637e91d53ecab0c8b980e58b7
diff --git a/realm/include/realm_rsi.h b/realm/include/realm_rsi.h
index 6bc80e1..9aa5540 100644
--- a/realm/include/realm_rsi.h
+++ b/realm/include/realm_rsi.h
@@ -683,6 +683,10 @@
 /* This function return RSI_ABI_VERSION */
 u_register_t rsi_get_version(u_register_t req_ver);
 
+/* This function returns RSI feature register at 'feature_reg_index' */
+u_register_t rsi_features(u_register_t feature_reg_index,
+			  u_register_t *feature_reg_value_ret);
+
 /* This function will initialize the attestation context */
 u_register_t rsi_attest_token_init(u_register_t challenge_0,
 				   u_register_t challenge_1,
@@ -709,4 +713,29 @@
 /* Function to enter aux plane. See RSI_PLANE_ENTER */
 u_register_t rsi_plane_enter(u_register_t plane_index, u_register_t run);
 
+u_register_t rsi_rdev_get_instance_id(u_register_t rdev_id,
+				      u_register_t *rdev_inst_id);
+
+u_register_t rsi_rdev_get_state(u_register_t rdev_id, u_register_t rdev_inst_id,
+				u_register_t *rdev_rsi_state);
+
+u_register_t rsi_rdev_get_measurements(u_register_t rdev_id,
+				       u_register_t rdev_inst_id,
+				       u_register_t meas_params_ptr);
+
+u_register_t rsi_rdev_get_info(u_register_t rdev_id, u_register_t rdev_inst_id,
+			       u_register_t rdev_info_ptr);
+
+u_register_t rsi_rdev_lock(u_register_t rdev_id, u_register_t rdev_inst_id);
+
+u_register_t rsi_rdev_get_interface_report(u_register_t rdev_id,
+					   u_register_t rdev_inst_id,
+					   u_register_t tdisp_version_max);
+
+u_register_t rsi_rdev_start(u_register_t rdev_id, u_register_t rdev_inst_id);
+
+u_register_t rsi_rdev_stop(u_register_t rdev_id, u_register_t rdev_inst_id);
+
+u_register_t rsi_rdev_continue(u_register_t rdev_id, u_register_t rdev_inst_id);
+
 #endif /* REALM_RSI_H */
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index 4988f52..4ed3367 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -33,6 +33,6 @@
 bool test_realm_attestation_fault(void);
 bool test_realm_mpam_undef_abort(void);
 bool test_realm_write_brbcr_el1_reg(void);
+bool test_realm_da_rsi_calls(void);
 
 #endif /* REALM_TESTS_H */
-
diff --git a/realm/realm.mk b/realm/realm.mk
index d9c1bec..690791b 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+# Copyright (c) 2022-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -43,6 +43,7 @@
 	realm_simd.c							\
 	realm_mpam.c							\
 	realm_brbe_tests.c						\
+	realm_da.c							\
 	)
 
 REALM_SOURCES += lib/${ARCH}/cache_helpers.S				\
diff --git a/realm/realm_da.c b/realm/realm_da.c
new file mode 100644
index 0000000..5c92af9
--- /dev/null
+++ b/realm/realm_da.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <realm_da_helpers.h>
+#include <realm_rsi.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <host_shared_data.h>
+#include <sync.h>
+
+/*
+ * Currently assigning one device is supported, for more than one device the VMM
+ * view of vdev_id and Realm view of device_id must match
+ */
+#define RDEV_ID				(0x0UL)
+
+#define RDEV_TDISP_VERSION_MAX		(0x10)
+
+struct rdev {
+	unsigned long id;
+	unsigned long inst_id;
+};
+
+static struct rdev gbl_rdev;
+
+/* Measurement parameters */
+static struct rsi_dev_measure_params gbl_rdev_meas_params
+__aligned(GRANULE_SIZE);
+
+/* RDEV info. decice type and attestation evidence digest */
+static struct rsi_dev_info gbl_rdev_info __aligned(GRANULE_SIZE);
+
+/* Get inst id for a known Realm device id RDEV_ID */
+static unsigned long realm_rdev_init(struct rdev *rdev, unsigned long rdev_id)
+{
+	u_register_t rsi_rc;
+	u_register_t rdev_inst_id;
+
+	memset(rdev, 0, sizeof(struct rdev));
+	realm_printf("In test_realm_da_rsi_calls\n");
+
+	rsi_rc = rsi_rdev_get_instance_id(rdev_id, &rdev_inst_id);
+	if (rsi_rc != RSI_SUCCESS) {
+		realm_printf("RSI_RDEV_GET_INSTANCE_ID failed: rdev_id: 0x%lx"
+			     " rsi_rc: 0x%lx\n", rdev_id, rsi_rc);
+		return rsi_rc;
+	}
+
+	rdev->id = rdev_id;
+	rdev->inst_id = rdev_inst_id;
+
+	realm_printf("RSI_RDEV_GET_INSTANCE_ID: rdev_id: 0x%lx, "
+		     "inst_id: 0x%lx\n", rdev_id, rdev_inst_id);
+
+	return RSI_SUCCESS;
+}
+
+static unsigned long realm_rsi_rdev_get_state(struct rdev *rdev)
+{
+	u_register_t rdev_rsi_state;
+	unsigned long rsi_rc;
+
+	rsi_rc = rsi_rdev_get_state(rdev->id, rdev->inst_id, &rdev_rsi_state);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_GET_STATE failed 0x%lx\n", rsi_rc);
+		return rsi_rc;
+	}
+
+	INFO("Realm: RSI_RDEV_GET_STATE completed. RDEV state: 0x%lx\n",
+	     rdev_rsi_state);
+
+	return RSI_SUCCESS;
+}
+
+static int realm_verify_device_attestation(struct rdev *rdev,
+					   struct rsi_dev_info *rdev_info)
+{
+	/*
+	 * todo: Implement RHI call to get cached device certificate,
+	 * measurement from host and verify the digest against RMM
+	 */
+	return 0;
+}
+
+static unsigned long realm_rsi_rdev_get_info(struct rdev *rdev,
+					     struct rsi_dev_info *rdev_info)
+{
+	unsigned long rsi_rc;
+
+	memset(rdev_info, 0, sizeof(struct rsi_dev_info));
+	rsi_rc = rsi_rdev_get_info(rdev->id, rdev->inst_id,
+				   (u_register_t)rdev_info);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_GET_INFO failed 0x%lx\n", rsi_rc);
+		return rsi_rc;
+	}
+
+	/* Print RDEV info */
+	INFO("RSI_RDEV_GET_INFO:\n");
+	INFO("\tflags: 0x%lx\n", rdev_info->flags);
+	INFO("\tattest_type: 0x%lx\n", rdev_info->attest_type);
+	INFO("\tcert_id: 0x%lx\n", rdev_info->cert_id);
+	INFO("\thash_algo: 0x%lx\n", rdev_info->hash_algo);
+
+	return RSI_SUCCESS;
+}
+
+static unsigned long
+realm_rsi_rdev_get_measurements(struct rdev *rdev,
+				struct rsi_dev_measure_params *mparams)
+{
+	unsigned long rsi_rc;
+
+	INFO("Realm: Call RSI_RDEV_GET_MEASUREMENTS\n");
+
+	/* Set measurement parameters */
+	memset(mparams, 0, sizeof(struct rsi_dev_measure_params));
+	mparams->flags = (INPLACE(RSI_DEV_MEASURE_FLAGS_ALL,
+				  RSI_DEV_MEASURE_ALL) |
+			  INPLACE(RSI_DEV_MEASURE_FLAGS_SIGNED,
+				  RSI_DEV_MEASURE_NOT_SIGNED) |
+			  INPLACE(RSI_DEV_MEASURE_FLAGS_RAW,
+				  RSI_DEV_MEASURE_NOT_RAW));
+
+
+	rsi_rc = rsi_rdev_get_measurements(rdev->id, rdev->inst_id,
+					   (u_register_t)mparams);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_GET_MEASUREMENTS failed\n");
+		return RSI_ERROR_STATE;
+	}
+
+	INFO("Host Realm: RDEV state after submitting meas request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	/* Do RSI RDEV continue call */
+	do {
+		rsi_rc = rsi_rdev_continue(rdev->id, rdev->inst_id);
+	} while (rsi_rc == RSI_INCOMPLETE);
+
+	INFO("Host Realm: RDEV state after host completing meas request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	return rsi_rc;
+}
+
+static unsigned long realm_rsi_rdev_lock(struct rdev *rdev)
+{
+	unsigned long rsi_rc;
+
+	INFO("Realm: Call RSI_RDEV_LOCK\n");
+
+	rsi_rc = rsi_rdev_lock(rdev->id, rdev->inst_id);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_LOCK failed\n");
+		return RSI_ERROR_STATE;
+	}
+
+	INFO("Realm: RDEV state after submitting lock request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	/* Do RSI RDEV continue call */
+	do {
+		rsi_rc = rsi_rdev_continue(rdev->id, rdev->inst_id);
+	} while (rsi_rc == RSI_INCOMPLETE);
+
+	INFO("Realm: RDEV state after host completing lock request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	return rsi_rc;
+}
+
+static unsigned long realm_rsi_rdev_get_interface_report(struct rdev *rdev)
+{
+	unsigned long rsi_rc;
+
+	INFO("Realm: Call RSI_RDEV_GET_IFC_REPORT\n");
+
+	rsi_rc = rsi_rdev_get_interface_report(rdev->id, rdev->inst_id,
+					       RDEV_TDISP_VERSION_MAX);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_GET_IFC_REPORT failed\n");
+		return RSI_ERROR_STATE;
+	}
+
+	INFO("Realm: RDEV state after submitting IFC_REPORT request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	/* Do RSI RDEV continue call */
+	do {
+		rsi_rc = rsi_rdev_continue(rdev->id, rdev->inst_id);
+	} while (rsi_rc == RSI_INCOMPLETE);
+
+	INFO("Realm: RDEV state after host completing IFC_REPORT request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	return rsi_rc;
+}
+
+static unsigned long realm_rsi_rdev_start(struct rdev *rdev)
+{
+	unsigned long rsi_rc;
+
+	INFO("Realm: Call RSI_RDEV_start\n");
+
+	rsi_rc = rsi_rdev_start(rdev->id, rdev->inst_id);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_START failed\n");
+		return RSI_ERROR_STATE;
+	}
+
+	INFO("Realm: RDEV state after submitting start request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	/* Do RSI RDEV continue call */
+	do {
+		rsi_rc = rsi_rdev_continue(rdev->id, rdev->inst_id);
+	} while (rsi_rc == RSI_INCOMPLETE);
+
+	INFO("Realm: RDEV state after host completing start request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	return rsi_rc;
+}
+
+static unsigned long realm_rsi_rdev_stop(struct rdev *rdev)
+{
+	unsigned long rsi_rc;
+
+	INFO("Realm: Call RSI_RDEV_STOP\n");
+
+	rsi_rc = rsi_rdev_stop(rdev->id, rdev->inst_id);
+	if (rsi_rc != RSI_SUCCESS) {
+		ERROR("RSI_RDEV_STOP failed\n");
+		return RSI_ERROR_STATE;
+	}
+
+	INFO("Realm: RDEV state after submitting stop request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	/* Do RSI RDEV continue call */
+	do {
+		rsi_rc = rsi_rdev_continue(rdev->id, rdev->inst_id);
+	} while (rsi_rc == RSI_INCOMPLETE);
+
+	INFO("Realm: RDEV state after host completing stop request\n");
+	(void)realm_rsi_rdev_get_state(rdev);
+
+	return rsi_rc;
+}
+
+/*
+ * If the Realm supports DA feature, this function calls series of RSI RDEV
+ * on the assigned device.
+ *
+ * Returns 'false' on success.
+ */
+bool test_realm_da_rsi_calls(void)
+{
+	struct rdev *rdev;
+	unsigned long rsi_rc;
+	u_register_t rsi_feature_reg0;
+	struct rsi_dev_measure_params *rdev_meas_params;
+	struct rsi_dev_info *rdev_info;
+
+	/* Check if RSI_FEATURES support DA */
+	rsi_rc = rsi_features(RSI_FEATURE_REGISTER_0_INDEX, &rsi_feature_reg0);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	if (EXTRACT(RSI_FEATURE_REGISTER_0_DA, rsi_feature_reg0) !=
+	    RSI_FEATURE_TRUE) {
+		realm_printf("RSI feature DA not supported for current Realm\n");
+		return false;
+	}
+
+	/* Get the global RDEV. Currently only one RDEV is supported */
+	rdev = &gbl_rdev;
+	rdev_meas_params = &gbl_rdev_meas_params;
+	rdev_info = &gbl_rdev_info;
+
+	rsi_rc = realm_rdev_init(rdev, RDEV_ID);
+	if (rdev == NULL) {
+		realm_printf("realm_rdev_init failed\n");
+		return false;
+	}
+
+	rsi_rc = realm_rsi_rdev_get_state(rdev);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	/* Before lock get_measurement */
+	rsi_rc = realm_rsi_rdev_get_measurements(rdev, rdev_meas_params);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	rsi_rc = realm_rsi_rdev_lock(rdev);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	/* After lock get_measurement */
+	rsi_rc = realm_rsi_rdev_get_measurements(rdev, rdev_meas_params);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	rsi_rc = realm_rsi_rdev_get_interface_report(rdev);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	/* After meas and ifc_report, get device info */
+	rsi_rc = realm_rsi_rdev_get_info(rdev, rdev_info);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	/*
+	 * Get cached device attestation from Host and verify it with device
+	 * attestation digest
+	 */
+	(void)realm_verify_device_attestation(rdev, rdev_info);
+
+	rsi_rc = realm_rsi_rdev_start(rdev);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	rsi_rc = realm_rsi_rdev_stop(rdev);
+	if (rsi_rc != RSI_SUCCESS) {
+		return false;
+	}
+
+	return true;
+}
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index a18e474..f36de11 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -630,6 +630,9 @@
 		case REALM_WRITE_BRBCR_EL1:
 			test_succeed = test_realm_write_brbcr_el1_reg();
 			break;
+		case REALM_DA_RSI_CALLS:
+			test_succeed = test_realm_da_rsi_calls();
+			break;
 		case REALM_PLANE_N_INST_FETCH_ABORT:
 			test_succeed = test_realm_plane_n_inst_fetch();
 			break;
diff --git a/realm/realm_rsi.c b/realm/realm_rsi.c
index 3ca4e8a..7316203 100644
--- a/realm/realm_rsi.c
+++ b/realm/realm_rsi.c
@@ -32,6 +32,22 @@
 	return res.ret1;
 }
 
+/* This function returns RSI feature register at 'feature_reg_index' */
+u_register_t rsi_features(u_register_t feature_reg_index,
+			  u_register_t *feature_reg_value_ret)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args) {SMC_RSI_FEATURES, feature_reg_index,
+				    0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
+	/* This command always returns RSI_SUCCESS */
+	if (res.ret0 == RSI_SUCCESS) {
+		*feature_reg_value_ret = res.ret1;
+	}
+
+	return res.ret0;
+}
+
 /* This function call Host and request to exit Realm with proper exit code */
 u_register_t rsi_exit_to_host(enum host_call_cmd exit_code)
 {
@@ -228,3 +244,126 @@
 			 register_encoding, value});
 	return res.ret0;
 }
+
+/* This function return instance ID of Realm device */
+u_register_t rsi_rdev_get_instance_id(u_register_t rdev_id,
+				      u_register_t *rdev_inst_id)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_GET_INSTANCE_ID, rdev_id, 0UL, 0UL, 0UL, 0UL,
+		 0UL, 0UL});
+
+	if (res.ret0 == RSI_SUCCESS) {
+		*rdev_inst_id = res.ret1;
+	}
+
+	return res.ret0;
+}
+
+/* This function return state of the Realm device */
+u_register_t rsi_rdev_get_state(u_register_t rdev_id, u_register_t rdev_inst_id,
+				u_register_t *rdev_rsi_state)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_GET_STATE, rdev_id, rdev_inst_id, 0UL, 0UL, 0UL,
+		 0UL, 0UL});
+
+	if (res.ret0 == RSI_SUCCESS) {
+		*rdev_rsi_state = res.ret1;
+	}
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to get_measurements */
+u_register_t rsi_rdev_get_measurements(u_register_t rdev_id,
+				       u_register_t rdev_inst_id,
+				       u_register_t meas_params_ptr)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_GET_MEASUREMENTS, rdev_id, rdev_inst_id,
+		 meas_params_ptr, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to get_measurements */
+u_register_t rsi_rdev_get_info(u_register_t rdev_id, u_register_t rdev_inst_id,
+			       u_register_t rdev_info_ptr)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		       {SMC_RSI_RDEV_GET_INFO, rdev_id, rdev_inst_id,
+			rdev_info_ptr, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to lock */
+u_register_t rsi_rdev_lock(u_register_t rdev_id, u_register_t rdev_inst_id)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_LOCK, rdev_id, rdev_inst_id,
+		 0UL, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to get interface report */
+u_register_t rsi_rdev_get_interface_report(u_register_t rdev_id,
+					   u_register_t rdev_inst_id,
+					   u_register_t tdisp_version_max)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_GET_INTERFACE_REPORT, rdev_id, rdev_inst_id,
+		 tdisp_version_max, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to start */
+u_register_t rsi_rdev_start(u_register_t rdev_id, u_register_t rdev_inst_id)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_START, rdev_id, rdev_inst_id,
+		 0UL, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function triggers RDEV interruptible operation to stop the TDI */
+u_register_t rsi_rdev_stop(u_register_t rdev_id, u_register_t rdev_inst_id)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		{SMC_RSI_RDEV_STOP, rdev_id, rdev_inst_id,
+		 0UL, 0UL, 0UL, 0UL, 0UL});
+
+	return res.ret0;
+}
+
+/* This function exits the REC to do vdev communicate */
+u_register_t rsi_rdev_continue(u_register_t rdev_id, u_register_t rdev_inst_id)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+		       {SMC_RSI_RDEV_CONTINUE, rdev_id, rdev_inst_id, 0UL, 0UL,
+			0UL, 0UL, 0UL});
+
+	return res.ret0;
+}