feat(rmm) : add api for rec force exit

add api to force exit a rec
added testcase for force exit rec

Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I56c70234e236c7d3615237d11c773bdb970012e3
diff --git a/include/runtime_services/host_realm_managment/host_realm_helper.h b/include/runtime_services/host_realm_managment/host_realm_helper.h
index b0a9e59..407c8e8 100644
--- a/include/runtime_services/host_realm_managment/host_realm_helper.h
+++ b/include/runtime_services/host_realm_managment/host_realm_helper.h
@@ -21,6 +21,7 @@
 		u_register_t ns_shared_mem_adr,
 		u_register_t ns_shared_mem_size);
 bool host_destroy_realm(void);
+void host_rec_send_sgi(unsigned int sgi, unsigned int rec_num);
 bool host_enter_realm_execute(uint8_t cmd, struct realm **realm_ptr,
 		int test_exit_reason, unsigned int rec_num);
 test_result_t host_cmp_result(void);
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 842ccb5..b1e54dd 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -508,6 +508,7 @@
 	u_register_t run[MAX_REC_COUNT];
 	u_register_t rec_flag[MAX_REC_COUNT];
 	u_register_t mpidr[MAX_REC_COUNT];
+	u_register_t host_mpidr[MAX_REC_COUNT];
 	u_register_t num_aux;
 	u_register_t rmm_feat_reg0;
 	u_register_t ipa_ns_buffer;
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index 83b21bf..b561fc5 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -41,6 +41,7 @@
  */
 enum realm_cmd {
 	REALM_SLEEP_CMD = 1U,
+	REALM_LOOP_CMD,
 	REALM_MULTIPLE_REC_PSCI_DENIED_CMD,
 	REALM_GET_RSI_VERSION,
 	REALM_PMU_CYCLE,
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 2271221..1440716 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -33,6 +33,13 @@
 	waitms(sleep);
 }
 
+static void realm_loop_cmd(void)
+{
+	while (true) {
+		waitms(500);
+	}
+}
+
 /*
  * This function requests RSI/ABI version from RMM.
  */
@@ -74,6 +81,10 @@
 			realm_sleep_cmd();
 			test_succeed = true;
 			break;
+		case REALM_LOOP_CMD:
+			realm_loop_cmd();
+			test_succeed = true;
+			break;
 		case REALM_MULTIPLE_REC_PSCI_DENIED_CMD:
 			test_succeed = test_realm_multiple_rec_psci_denied_cmd();
 			break;
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
index 51b058c..a3a07db 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
@@ -15,9 +15,11 @@
 #include <host_realm_mem_layout.h>
 #include <host_realm_rmi.h>
 #include <host_shared_data.h>
+#include <platform.h>
 #include <plat_topology.h>
 #include <power_management.h>
 #include <realm_def.h>
+#include <sgi.h>
 #include <test_helpers.h>
 #include <xlat_tables_v2.h>
 
@@ -336,3 +338,26 @@
 	return TEST_RESULT_FAIL;
 }
 
+/*
+ * Returns Host core position for specified Rec
+ * Host mpidr is saved on every rec enter
+ */
+static unsigned int host_realm_find_core_pos_by_rec(unsigned int rec_num)
+{
+	if (rec_num < MAX_REC_COUNT && realm.run[rec_num] != 0U) {
+		return platform_get_core_pos(realm.host_mpidr[rec_num]);
+	}
+	return (unsigned int)-1;
+}
+
+/*
+ * Send SGI on core running specified Rec
+ * API can be used to forcefully exit from Realm
+ */
+void host_rec_send_sgi(unsigned int sgi, unsigned int rec_num)
+{
+	unsigned int core_pos = host_realm_find_core_pos_by_rec(rec_num);
+	if (core_pos < PLATFORM_CORE_COUNT) {
+		tftf_send_sgi(sgi, core_pos);
+	}
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
index 47713d5..a897913 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
@@ -1231,6 +1231,7 @@
 	}
 
 	run = (struct rmi_rec_run *)realm->run[rec_num];
+	realm->host_mpidr[rec_num] = read_mpidr_el1();
 	do {
 		re_enter_rec = false;
 		ret = host_rmi_handler(&(smc_args) {RMI_REC_ENTER,
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
index 1208d62..916e848 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
@@ -5,9 +5,13 @@
  */
 
 #include <stdlib.h>
+#include <drivers/arm/arm_gic.h>
 #include <debug.h>
+#include <platform.h>
+#include <plat_topology.h>
 #include <power_management.h>
 #include <psci.h>
+#include <sgi.h>
 #include <test_helpers.h>
 
 #include <host_realm_helper.h>
@@ -15,6 +19,7 @@
 #include <host_realm_pmu.h>
 #include <host_shared_data.h>
 
+static uint64_t is_secondary_cpu_on;
 /*
  * Test tries to create max Rec
  * Enters all Rec from single CPU
@@ -196,3 +201,84 @@
 
 	return host_cmp_result();
 }
+
+/* Lock used to avoid concurrent accesses to the secondary_cpu_on counter */
+spinlock_t secondary_cpu_lock;
+
+static test_result_t cpu_on_handler2(void)
+{
+	bool ret;
+
+	spin_lock(&secondary_cpu_lock);
+	is_secondary_cpu_on++;
+	spin_unlock(&secondary_cpu_lock);
+
+	ret = host_enter_realm_execute(REALM_LOOP_CMD, NULL, RMI_EXIT_IRQ, is_secondary_cpu_on);
+	if (!ret) {
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+test_result_t host_realm_multi_rec_exit_irq(void)
+{
+	bool ret1, ret2;
+	unsigned int rec_count = MAX_REC_COUNT;
+	u_register_t other_mpidr, my_mpidr, ret;
+	int cpu_node;
+	u_register_t rec_flag[] = {RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,
+		RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,
+		RMI_RUNNABLE};
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+	SKIP_TEST_IF_LESS_THAN_N_CPUS(rec_count);
+
+	if (!host_create_realm_payload((u_register_t)REALM_IMAGE_BASE,
+			(u_register_t)PAGE_POOL_BASE,
+			(u_register_t)(PAGE_POOL_MAX_SIZE +
+			NS_REALM_SHARED_MEM_SIZE),
+			(u_register_t)PAGE_POOL_MAX_SIZE,
+			0UL, rec_flag, rec_count)) {
+		return TEST_RESULT_FAIL;
+	}
+	if (!host_create_shared_mem(NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	is_secondary_cpu_on = 0U;
+	my_mpidr = read_mpidr_el1() & MPID_MASK;
+	ret1 = host_enter_realm_execute(REALM_GET_RSI_VERSION, NULL, RMI_EXIT_HOST_CALL, 0U);
+	for_each_cpu(cpu_node) {
+		other_mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (other_mpidr == my_mpidr) {
+			continue;
+		}
+		/* Power on the other CPU */
+		ret = tftf_try_cpu_on(other_mpidr, (uintptr_t)cpu_on_handler2, 0);
+		if (ret != PSCI_E_SUCCESS) {
+			goto destroy_realm;
+		}
+	}
+
+	INFO("Wait for all CPU to come up\n");
+	while (is_secondary_cpu_on != (rec_count - 1U)) {
+		waitms(100U);
+	}
+
+destroy_realm:
+	tftf_irq_enable(IRQ_NS_SGI_7, GIC_HIGHEST_NS_PRIORITY);
+	for (unsigned int i = 1U; i < rec_count; i++) {
+		INFO("Raising NS IRQ for rec %d\n", i);
+		host_rec_send_sgi(IRQ_NS_SGI_7, i);
+	}
+	tftf_irq_disable(IRQ_NS_SGI_7);
+	ret2 = host_destroy_realm();
+	if (!ret1 || !ret2) {
+		ERROR("%s(): enter=%d destroy=%d\n",
+		__func__, ret1, ret2);
+		return TEST_RESULT_FAIL;
+	}
+
+	return host_cmp_result();
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index fb65837..f0ae8c6 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -14,6 +14,8 @@
 	  function="host_realm_multi_rec_single_cpu" />
 	  <testcase name="Realm payload multi rec psci denied"
 	  function="host_realm_multi_rec_psci_denied" />
+	  <testcase name="Realm payload multi rec force exit on NS IRQ"
+	  function="host_realm_multi_rec_exit_irq" />
 	  <testcase name="Realm payload boot"
 	  function="host_realm_version_single_cpu" />
 	  <testcase name="Realm payload multi CPU request"