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;
}