feat(realm): add support for RSI_IPA_STATE_GET/SET

Add support for realm API rsi_ipa_state_set, rsi_ipa_state_get
Add testcase for following
* Realm calls rsi_ipa_state_set to change RIPAS=RAM,
* Host accepts and call RMI_RTT_SET_RIPAS
* Realm verifies RIPAS change was successful

Change-Id: I4da6c7d25faa62afde1d0f682510bac6c8445821
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
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 bfb3384..6f3f227 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -558,5 +558,15 @@
 		unsigned long status);
 void host_rmi_init_cmp_result(void);
 bool host_rmi_get_cmp_result(void);
+u_register_t host_realm_map_protected_data(bool unknown,
+			struct realm *realm,
+			u_register_t target_pa,
+			u_register_t map_size,
+			u_register_t src_pa);
+u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
+				  u_register_t rec,
+				  u_register_t start,
+				  u_register_t end,
+				  u_register_t *top);
 
 #endif /* HOST_REALM_RMI_H */
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 fd764c6..e674f46 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -52,6 +52,7 @@
 	REALM_PMU_INTERRUPT,
 	REALM_REQ_FPU_FILL_CMD,
 	REALM_REQ_FPU_CMP_CMD,
+	REALM_SET_RIPAS_CMD,
 	REALM_SVE_RDVL,
 	REALM_SVE_ID_REGISTERS,
 	REALM_SVE_PROBE_VL,
@@ -71,7 +72,8 @@
  */
 enum host_param_index {
 	HOST_CMD_INDEX = 0U,
-	HOST_ARG1_INDEX
+	HOST_ARG1_INDEX,
+	HOST_ARG2_INDEX
 };
 
 enum host_call_cmd {
diff --git a/realm/include/realm_rsi.h b/realm/include/realm_rsi.h
index 547db0d..8436db9 100644
--- a/realm/include/realm_rsi.h
+++ b/realm/include/realm_rsi.h
@@ -100,6 +100,33 @@
  * arg0 == struct rsi_realm_config address
  */
 #define RSI_REALM_CONFIG	SMC_RSI_FID(6U)
+#define RSI_IPA_STATE_SET	SMC_RSI_FID(7U)
+#define RSI_IPA_STATE_GET	SMC_RSI_FID(8U)
+
+typedef enum {
+	RSI_EMPTY = 0U,
+	RSI_RAM,
+	RSI_DESTROYED
+} rsi_ripas_type;
+
+typedef enum {
+	RSI_ACCEPT = 0U,
+	RSI_REJECT
+} rsi_ripas_respose_type;
+
+#define RSI_NO_CHANGE_DESTROYED	0UL
+#define RSI_CHANGE_DESTROYED	1UL
+
+/* Request RIPAS of a target IPA range to be changed to a specified value. */
+u_register_t rsi_ipa_state_set(u_register_t base,
+			   u_register_t top,
+			   rsi_ripas_type ripas,
+			   u_register_t flag,
+			   u_register_t *new_base,
+			   rsi_ripas_respose_type *response);
+
+/* Request RIPAS of a target IPA */
+u_register_t rsi_ipa_state_get(u_register_t adr, rsi_ripas_type *ripas);
 
 /* This function return RSI_ABI_VERSION */
 u_register_t rsi_get_version(u_register_t req_ver);
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 563c643..9b2be83 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -20,7 +20,6 @@
 
 static fpu_state_t rl_fpu_state_write;
 static fpu_state_t rl_fpu_state_read;
-
 /*
  * This function reads sleep time in ms from shared buffer and spins PE
  * in a loop for that time period.
@@ -61,6 +60,47 @@
 	return true;
 }
 
+bool test_realm_set_ripas(void)
+{
+	u_register_t ret, base, new_base, top;
+	rsi_ripas_respose_type response;
+	rsi_ripas_type ripas;
+
+	base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+	top = realm_shared_data_get_my_host_val(HOST_ARG2_INDEX);
+	realm_printf("base=0x%lx top =0x%lx\n", base, top);
+	ret = rsi_ipa_state_get(base, &ripas);
+	if (ripas != RSI_EMPTY) {
+		return false;
+	}
+
+	ret = rsi_ipa_state_set(base, top, RSI_RAM,
+		RSI_NO_CHANGE_DESTROYED, &new_base, &response);
+	if (ret != RSI_SUCCESS || response != RSI_ACCEPT) {
+		return false;
+	}
+	while (new_base < top) {
+		realm_printf("new_base=0x%lx top =0x%lx\n", new_base, top);
+		ret = rsi_ipa_state_set(new_base, top, RSI_RAM,
+				RSI_NO_CHANGE_DESTROYED, &new_base, &response);
+		if (ret != RSI_SUCCESS || response != RSI_ACCEPT) {
+			realm_printf("rsi_ipa_state_set failed\n");
+			return false;
+		}
+	}
+
+	/* Verify that RIAS has changed for range base-top. */
+	for (unsigned int i = 0U; (base + (PAGE_SIZE * i) < top); i++) {
+		ret = rsi_ipa_state_get(base + (PAGE_SIZE * i), &ripas);
+		if (ret != RSI_SUCCESS || ripas != RSI_RAM) {
+			realm_printf("rsi_ipa_state_get failed base=0x%lx, ripas=0x%x\n",
+					base + (PAGE_SIZE * i), ripas);
+			return false;
+		}
+	}
+	return true;
+}
+
 /*
  * This is the entry function for Realm payload, it first requests the shared buffer
  * IPA address from Host using HOST_CALL/RSI, it reads the command to be executed,
@@ -122,6 +162,9 @@
 			test_succeed = !fpu_state_compare(&rl_fpu_state_write,
 							  &rl_fpu_state_read);
 			break;
+		case REALM_SET_RIPAS_CMD:
+			test_succeed = test_realm_set_ripas();
+			break;
 		case REALM_SVE_RDVL:
 			test_succeed = test_realm_sve_rdvl();
 			break;
diff --git a/realm/realm_rsi.c b/realm/realm_rsi.c
index ba60ba8..04f57fc 100644
--- a/realm/realm_rsi.c
+++ b/realm/realm_rsi.c
@@ -51,3 +51,35 @@
 	tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
 		0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
 }
+
+/* This function will exit to the Host to request RIPAS CHANGE of IPA range */
+u_register_t rsi_ipa_state_set(u_register_t base,
+			       u_register_t top,
+			       rsi_ripas_type ripas,
+			       u_register_t flag,
+			       u_register_t *new_base,
+			       rsi_ripas_respose_type *response)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+			{RSI_IPA_STATE_SET, base, top, ripas, flag});
+	if (res.ret0 == RSI_SUCCESS) {
+		*new_base = res.ret1;
+		*response = res.ret2;
+	}
+	return res.ret0;
+}
+
+/* This function will return RIPAS of IPA */
+u_register_t rsi_ipa_state_get(u_register_t adr, rsi_ripas_type *ripas)
+{
+	smc_ret_values res = {};
+
+	res = tftf_smc(&(smc_args)
+			{RSI_IPA_STATE_GET, adr});
+	if (res.ret0 == RSI_SUCCESS) {
+		*ripas = res.ret1;
+	}
+	return res.ret0;
+}
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 53b55fe..c678217 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
@@ -110,11 +110,11 @@
 				target_rec, status}, 4U)).ret0;
 }
 
-static inline u_register_t host_rmi_data_create(bool unknown,
-						u_register_t rd,
-						u_register_t data,
-						u_register_t map_addr,
-						u_register_t src)
+u_register_t host_rmi_data_create(bool unknown,
+				  u_register_t rd,
+				  u_register_t data,
+				  u_register_t map_addr,
+				  u_register_t src)
 {
 	if (unknown) {
 		return host_rmi_handler(&(smc_args) {RMI_DATA_CREATE_UNKNOWN,
@@ -240,11 +240,11 @@
 	return rets.ret0;
 }
 
-static inline u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
-						  u_register_t rec,
-						  u_register_t start,
-						  u_register_t end,
-						  u_register_t *top)
+u_register_t host_rmi_rtt_set_ripas(u_register_t rd,
+				    u_register_t rec,
+				    u_register_t start,
+				    u_register_t end,
+				    u_register_t *top)
 {
 	smc_ret_values rets;
 
@@ -381,16 +381,16 @@
 
 }
 
-static u_register_t host_realm_map_protected_data(bool unknown,
-						  struct realm *realm,
-						  u_register_t target_pa,
-						  u_register_t map_size,
-						  u_register_t src_pa)
+u_register_t host_realm_map_protected_data(bool unknown,
+					   struct realm *realm,
+					   u_register_t target_pa,
+					   u_register_t map_size,
+					   u_register_t src_pa)
 {
 	u_register_t rd = realm->rd;
 	u_register_t map_level, level;
 	u_register_t ret = 0UL;
-	u_register_t size;
+	u_register_t size = 0UL;
 	u_register_t phys = target_pa;
 	u_register_t map_addr = target_pa;
 	u_register_t end_addr = map_addr + map_size;
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
index 56afafa..0fd65fd 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
@@ -12,6 +12,7 @@
 #include <irq.h>
 #include <drivers/arm/arm_gic.h>
 #include <drivers/arm/gic_v3.h>
+#include <heap/page_alloc.h>
 #include <pauth.h>
 #include <test_helpers.h>
 
@@ -412,3 +413,103 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/*
+ * Test set_ripas functionality in Realm
+ * Test allocates 3 PAGES and passes to Realm
+ * Realm: verifies that initial RIPAS of these pages is EMPTY
+ * Realm: requests RIPAS Change to RAM
+ * Host: attempt to change RIPAS outside requested range, verifies error generated by RMM
+ * Host: changes RIPAS of first PAGE and re-enters Realm
+ * Realm: tracks progress and requests RIPAS Change to RAM till all pages are complete
+ * Host: changes RIPAS of requested PAGE and re-enters Realm
+ * Realm: verifies all PAGES are set to RIPAS=RAM
+ */
+test_result_t host_realm_set_ripas(void)
+{
+	bool ret1, ret2;
+	u_register_t ret, base, new_base, exit_reason;
+	unsigned int host_call_result = TEST_RESULT_FAIL;
+	struct realm realm;
+	struct rmi_rec_run *run;
+	u_register_t rec_flag[1] = {RMI_RUNNABLE};
+	u_register_t test_page_num = 3U;
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+			(u_register_t)PAGE_POOL_BASE,
+			(u_register_t)PAGE_POOL_MAX_SIZE,
+			0UL, rec_flag, 1U)) {
+		return TEST_RESULT_FAIL;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, 10U);
+	ret1 = host_enter_realm_execute(&realm, REALM_SLEEP_CMD, RMI_EXIT_HOST_CALL, 0U);
+	base = (u_register_t)page_alloc(PAGE_SIZE * test_page_num);
+	host_shared_data_set_host_val(&realm, 0U, HOST_ARG1_INDEX, base);
+	host_shared_data_set_host_val(&realm, 0U, HOST_ARG2_INDEX,
+			base + (PAGE_SIZE * test_page_num));
+
+	for (unsigned int i = 0U; i < test_page_num; i++) {
+		ret = host_realm_map_protected_data(true, &realm,
+				base + (PAGE_SIZE * i), PAGE_SIZE,
+				base + (PAGE_SIZE * i));
+		if (ret != REALM_SUCCESS) {
+			ERROR("host_realm_map_protected_data failed\n");
+			goto destroy_realm;
+		}
+	}
+	ret1 = host_enter_realm_execute(&realm, REALM_SET_RIPAS_CMD,
+			RMI_EXIT_RIPAS_CHANGE, 0U);
+	if (!ret1) {
+		ERROR("Rec enter failed\n");
+		goto destroy_realm;
+	}
+	run = (struct rmi_rec_run *)realm.run[0U];
+
+	/* Attemp to set ripas for IPA out of requested range, expect error */
+	ret = host_rmi_rtt_set_ripas(realm.rd,
+				     realm.rec[0U],
+				     run->exit.ripas_base - PAGE_SIZE,
+				     run->exit.ripas_base,
+				     &new_base);
+	if (ret != RMI_ERROR_INPUT || new_base != 0U) {
+		ERROR("host_rmi_rtt_set_ripas should have failed ret = 0x%lx\n", ret);
+		goto destroy_realm;
+	}
+
+	while (run->exit.ripas_base <= base + (PAGE_SIZE * test_page_num)) {
+		INFO("host_rmi_rtt_set_ripas ripas_base=0x%lx\n",
+				run->exit.ripas_base);
+		ret = host_rmi_rtt_set_ripas(realm.rd,
+					     realm.rec[0U],
+					     run->exit.ripas_base,
+					     run->exit.ripas_base + PAGE_SIZE,
+					     &new_base);
+		if (ret != RMI_SUCCESS) {
+			ERROR("host_rmi_rtt_set_ripas failed ret = 0x%lx\n", ret);
+			goto destroy_realm;
+		}
+		ret = host_realm_rec_enter(&realm,
+			&exit_reason, &host_call_result, 0U);
+		if (ret != RMI_SUCCESS || exit_reason != RMI_EXIT_RIPAS_CHANGE) {
+			goto destroy_realm;
+		}
+	}
+destroy_realm:
+	ret2 = host_destroy_realm(&realm);
+
+	if (!ret2) {
+		ERROR("%s(): destroy=%d\n",
+		__func__, ret2);
+		return TEST_RESULT_FAIL;
+	}
+
+	page_free(base);
+	return host_call_result;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 137a768..bcc72ec 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -42,6 +42,8 @@
 	  function="host_realm_sec_interrupt_can_preempt_rl" />
 	  <testcase name="Check that FPU state registers context is preserved in RL/SE/NS"
 	  function="host_realm_fpu_access_in_rl_ns_se" />
+	  <testcase name="Realm request set_ripas"
+	  function="host_realm_set_ripas" />
 	  <!-- Test case related to SVE support and SIMD state -->
 	  <testcase name="Check RMI reports proper SVE VL"
 	  function="host_check_rmi_reports_proper_sve_vl" />