fix(rsi): handle destroyed state s2tte in RSI_IPA_STATE_GET ABI

In the RSI_IPA_STATE_GET ABI implementation, if the s2tte has state
HIPAS=DESTROYED for the given IPA, then emulate a Data Abort and exit
to the Host.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: If909fcac74748052f98f3f4d190ceb3cc6c2fbc8
diff --git a/lib/realm/include/realm.h b/lib/realm/include/realm.h
index e34fa10..24c0202 100644
--- a/lib/realm/include/realm.h
+++ b/lib/realm/include/realm.h
@@ -241,6 +241,7 @@
 				    unsigned long ipa,
 				    struct s2_walk_result *res);
 
-void realm_ipa_get_ripas(struct rec *rec, unsigned long ipa,
-			 enum ripas *ripas_ptr, bool *s2tte_destroyed);
+enum s2_walk_status realm_ipa_get_ripas(struct rec *rec, unsigned long ipa,
+					enum ripas *ripas_ptr,
+					unsigned long *rtt_level);
 #endif /* REALM_H */
diff --git a/runtime/core/exit.c b/runtime/core/exit.c
index b16fc5a..cf6839c 100644
--- a/runtime/core/exit.c
+++ b/runtime/core/exit.c
@@ -461,7 +461,7 @@
 		rec->regs[0] = handle_rsi_extend_measurement(rec);
 		break;
 	case SMC_RSI_REALM_CONFIG: {
-		struct rsi_config_result res;
+		struct rsi_walk_smc_result res;
 
 		res = handle_rsi_realm_config(rec);
 		if (res.walk_result.abort) {
@@ -483,12 +483,17 @@
 		}
 		break;
 	case SMC_RSI_IPA_STATE_GET: {
-		enum ripas ripas;
+		struct rsi_walk_smc_result res;
 
-		rec->regs[0] = handle_rsi_ipa_state_get(rec, rec->regs[1],
-							&ripas);
-		if (rec->regs[0] == RSI_SUCCESS) {
-			rec->regs[1] = ripas;
+		res = handle_rsi_ipa_state_get(rec);
+		if (res.walk_result.abort) {
+			emulate_stage2_data_abort(rec, rec_exit,
+						  res.walk_result.rtt_level);
+			/* Exit to Host */
+			ret_to_rec = false;
+		} else {
+			/* Exit to Realm */
+			return_result_to_realm(rec, res.smc_res);
 		}
 		break;
 	}
diff --git a/runtime/include/rsi-config.h b/runtime/include/rsi-config.h
index aaa3fe5..24f2075 100644
--- a/runtime/include/rsi-config.h
+++ b/runtime/include/rsi-config.h
@@ -7,23 +7,9 @@
 #define RSI_CONFIG_H
 
 #include <rsi-walk.h>
-#include <smc.h>
 
 struct rec;
 
-struct rsi_config_result {
-	/*
-	 * Result of RTT walk performed by RSI command.
-	 */
-	struct rsi_walk_result walk_result;
-
-	/*
-	 * If @walk_result.abort is false, @smc_res contains GPR values to be
-	 * returned to the Realm.
-	 */
-	struct smc_result smc_res;
-};
-
-struct rsi_config_result handle_rsi_realm_config(struct rec *rec);
+struct rsi_walk_smc_result handle_rsi_realm_config(struct rec *rec);
 
 #endif /* RSI_CONFIG_H */
diff --git a/runtime/include/rsi-memory.h b/runtime/include/rsi-memory.h
index e74e15e..ee9cfb1 100644
--- a/runtime/include/rsi-memory.h
+++ b/runtime/include/rsi-memory.h
@@ -6,14 +6,13 @@
 #ifndef	RSI_MEMORY_H
 #define	RSI_MEMORY_H
 
-#include <smc-rsi.h>
+#include <rsi-walk.h>
 
 struct rec;
 struct rmi_rec_exit;
 
 bool handle_rsi_ipa_state_set(struct rec *rec, struct rmi_rec_exit *rec_exit);
 
-rsi_status_t handle_rsi_ipa_state_get(struct rec *rec, unsigned long ipa,
-				      enum ripas *ripas);
+struct rsi_walk_smc_result handle_rsi_ipa_state_get(struct rec *rec);
 
 #endif /* RSI_MEMORY_H */
diff --git a/runtime/include/rsi-walk.h b/runtime/include/rsi-walk.h
index 01ff6c1..a009266 100644
--- a/runtime/include/rsi-walk.h
+++ b/runtime/include/rsi-walk.h
@@ -6,6 +6,8 @@
 #ifndef RSI_WALK_H
 #define RSI_WALK_H
 
+struct smc_result;
+
 struct rsi_walk_result {
 	/*
 	 * If true, RTT walk failed due to missing PTE at level @rtt_level.
@@ -17,4 +19,15 @@
 	unsigned long rtt_level;
 };
 
+struct rsi_walk_smc_result {
+	/* Result of RTT walk performed by RSI command */
+	struct rsi_walk_result walk_result;
+
+	/*
+	 * If @walk_result.abort is false, @smc_res contains GPR values to be
+	 * returned to the Realm.
+	 */
+	struct smc_result smc_res;
+};
+
 #endif /* RSI_WALK_H */
diff --git a/runtime/rsi/config.c b/runtime/rsi/config.c
index 38a6446..33b9cdf 100644
--- a/runtime/rsi/config.c
+++ b/runtime/rsi/config.c
@@ -9,9 +9,9 @@
 #include <rsi-walk.h>
 #include <smc-rsi.h>
 
-struct rsi_config_result  handle_rsi_realm_config(struct rec *rec)
+struct rsi_walk_smc_result  handle_rsi_realm_config(struct rec *rec)
 {
-	struct rsi_config_result res = { 0 };
+	struct rsi_walk_smc_result res = { 0 };
 	unsigned long ipa = rec->regs[1];
 	struct rd *rd;
 	enum s2_walk_status walk_status;
diff --git a/runtime/rsi/memory.c b/runtime/rsi/memory.c
index c59272b..49c40bc 100644
--- a/runtime/rsi/memory.c
+++ b/runtime/rsi/memory.c
@@ -51,24 +51,32 @@
 	return false;
 }
 
-rsi_status_t handle_rsi_ipa_state_get(struct rec *rec, unsigned long ipa,
-				      enum ripas *ripas_ptr)
+struct rsi_walk_smc_result handle_rsi_ipa_state_get(struct rec *rec)
 {
-	bool s2tte_destroyed;
+	struct rsi_walk_smc_result res = { 0 };
+	enum s2_walk_status ws;
+	unsigned long rtt_level, ipa;
+	enum ripas ripas;
 
-	if (!GRANULE_ALIGNED(ipa)) {
-		return RSI_ERROR_INPUT;
+	ipa = rec->regs[1];
+
+	/* Exit to realm */
+	res.walk_result.abort = false;
+
+	if (!GRANULE_ALIGNED(ipa) || !addr_in_rec_par(rec, ipa)) {
+		res.smc_res.x[0] = RSI_ERROR_INPUT;
+		return res;
 	}
 
-	if (!addr_in_rec_par(rec, ipa)) {
-		return RSI_ERROR_INPUT;
+	ws = realm_ipa_get_ripas(rec, ipa, &ripas, &rtt_level);
+	if (ws == WALK_SUCCESS) {
+		res.smc_res.x[0] = RSI_SUCCESS;
+		res.smc_res.x[1] = ripas;
+	} else {
+		/* Exit to Host */
+		res.walk_result.abort = true;
+		res.walk_result.rtt_level = rtt_level;
 	}
 
-	realm_ipa_get_ripas(rec, ipa, ripas_ptr, &s2tte_destroyed);
-	if (s2tte_destroyed == true) {
-		/* TODO: handle destroyed state appropriately */
-		return RSI_ERROR_INPUT;
-	}
-
-	return RSI_SUCCESS;
+	return res;
 }
diff --git a/runtime/rsi/realm_ipa_helper.c b/runtime/rsi/realm_ipa_helper.c
index d6e38e9..26078ba 100644
--- a/runtime/rsi/realm_ipa_helper.c
+++ b/runtime/rsi/realm_ipa_helper.c
@@ -99,19 +99,24 @@
  * Parameters:
  *	[in]  @rec:		Pointer to the rec
  *	[in]  @ipa:		IPA for which RIPAS is queried.
- *	[out] @ripas_ptr:	RIPAS value returned for the IPA
- *	[out] @s2tte_destroyed: Set to true when s2tte has HIPAS=DESTROYED
+ *	[out] @ripas_ptr:	RIPAS value returned for the IPA. This is set in
+ *				case of WALK_SUCCESS is returned.
+ *	[out] @rtt_level:	Value of last level reached by table walk. This
+ *				is set in case of WALK_FAIL is returned.
  * Returns:
- *	None
+ *	WALK_SUCCESS:		RIPAS of IPA found
+ *	WALK_FAIL:		RIPAS of IPA not found. s2tte has HIPAS=DESTROYED
  */
-void realm_ipa_get_ripas(struct rec *rec, unsigned long ipa,
-			 enum ripas *ripas_ptr, bool *s2tte_destroyed)
+enum s2_walk_status realm_ipa_get_ripas(struct rec *rec, unsigned long ipa,
+					enum ripas *ripas_ptr,
+					unsigned long *rtt_level)
 {
 	unsigned long s2tte, *ll_table;
 	struct rtt_walk wi;
+	enum s2_walk_status ws;
 
 	assert(ripas_ptr != NULL);
-	assert(s2tte_destroyed != NULL);
+	assert(rtt_level != NULL);
 	assert(GRANULE_ALIGNED(ipa));
 	assert(addr_in_rec_par(rec, ipa));
 
@@ -126,12 +131,20 @@
 	s2tte = s2tte_read(&ll_table[wi.index]);
 
 	if (s2tte_is_destroyed(s2tte)) {
-		*s2tte_destroyed = true;
+		*rtt_level = wi.last_level;
+		/*
+		 * The IPA has been destroyed by NS Host. Return data_abort back
+		 * to NS Host and there is no recovery possible of this Rec
+		 * after this.
+		 */
+		ws = WALK_FAIL;
 	} else {
-		*s2tte_destroyed = false;
 		*ripas_ptr = s2tte_get_ripas(s2tte);
+		ws = WALK_SUCCESS;
 	}
 
 	buffer_unmap(ll_table);
 	granule_unlock(wi.g_llt);
+
+	return ws;
 }