feat(rmm): unify design of RSI/PSCI handlers

This patch modifies RSI handlers to use consistent design
pattern. It eliminates the split of responsibility between
the 'handle_realm_rsi' dispatcher function and ther handler
function varied between commands, e.g.:

- Among commands which only have a single return value (in X0),
  some set X1-X3 to zero (e.g. RSI_REALM_CONFIG), while
  others leave caller values in X1-X3 (e.g. RSI_HOST_CALL).

- Among commands which cause a REC exit to the Host, the exit
  reason is in some cases set by the dispatcher (e.g.
  RSI_ATTESTATION_TOKEN_CONTINUE exiting due to a pending IRQ)
  and in others (e.g. RSI_IPA_STATE_SET) is set by the handler.

- In some cases all of the command logic is contained within
  the handler (e.g. RSI_VERSION, RSI_ATTESTATION_TOKEN_INIT,
  RSI_MEASUREMENT_READ, RSI_MEASUREMENT_EXTEND), while in
  others a significant part of the command logic is implemented
  by the handler (in particular RSI_ATTESTATION_TOKEN_CONTINUE
  and RSI_HOST_CALL).

These discrepancies made it difficult to follow the program
flow, and added complexity for implementation of new commands
or modification of the existing ones.

This commit introduces the following design pattern:

- All RSI and PSCI commands handlers have "void" return value
 and pointer to 'struct rsi_result' type parameter. It contains
 an "action" enumeration, which informs the dispatcher to do
 one of the following:
 - Return to the Realm, passing GPRs provided by the handler.
 - Exit to the Host, with 'rec_exit' fields (including
   exit_reason) populated by the handler.
 - Exit to the Host due to a Stage 2 translation fault.

- When GPRs are returned to the Realm, X0-X3 are always updated
  (with non-result registers being zero).

- The dispatcher contains only a switch over FID, and the logic
  necessary to perform the actions listed above. All other
  logic for a given command is contained within the handler itself.

This commit includes no changes to functionality.

Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
Change-Id: Iba80b679ca5aa9d83ba6c876e9d48b7b0b0d2579
diff --git a/runtime/rsi/host_call.c b/runtime/rsi/host_call.c
index 3a008ef..24ce759 100644
--- a/runtime/rsi/host_call.c
+++ b/runtime/rsi/host_call.c
@@ -26,10 +26,9 @@
  *     results to host call data structure (in Realm memory).
  *   - Return value is RSI_SUCCESS.
  */
-static unsigned int do_host_call(struct rec *rec,
-				 struct rmi_rec_exit *rec_exit,
-				 struct rmi_rec_entry *rec_entry,
-				 struct rsi_walk_result *rsi_walk_result)
+static void do_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
+			 struct rmi_rec_entry *rec_entry,
+			 struct rsi_result *res)
 {
 	enum s2_walk_status walk_status;
 	struct s2_walk_result walk_result;
@@ -39,7 +38,6 @@
 	unsigned char *data;
 	struct rsi_host_call *host_call;
 	unsigned int i;
-	unsigned int ret = RSI_SUCCESS;
 
 	assert(addr_in_rec_par(rec, ipa));
 
@@ -54,12 +52,12 @@
 		break;
 	case WALK_FAIL:
 		if (walk_result.ripas_val == RIPAS_EMPTY) {
-			ret = RSI_ERROR_INPUT;
+			res->smc_res.x[0] = RSI_ERROR_INPUT;
 		} else {
-			rsi_walk_result->abort = true;
-			rsi_walk_result->rtt_level = walk_result.rtt_level;
+			res->action = STAGE_2_TRANSLATION_FAULT;
+			res->rtt_level = walk_result.rtt_level;
 		}
-		return ret;
+		return;
 	case WALK_INVALID_PARAMS:
 		assert(false);
 		break;
@@ -76,11 +74,24 @@
 		for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
 			rec_exit->gprs[i] = host_call->gprs[i];
 		}
+
+		/* Record that a host call is pending */
+		rec->host_call = true;
+
+		/*
+		 * Notify the Host.
+		 * Leave REC registers unchanged,
+		 * these will be read and updated by complete_rsi_host_call.
+		 */
+		res->action = EXIT_TO_HOST;
+		rec_exit->exit_reason = RMI_EXIT_HOST_CALL;
 	} else {
 		/* Copy host call results to host call data structure */
 		for (i = 0U; i < RSI_HOST_CALL_NR_GPRS; i++) {
 			host_call->gprs[i] = rec_entry->gprs[i];
 		}
+
+		rec->regs[0] = RSI_SUCCESS;
 	}
 
 	/* Unmap Realm data granule */
@@ -88,41 +99,39 @@
 
 	/* Unlock last level RTT */
 	granule_unlock(walk_result.llt);
-
-	return ret;
 }
 
-struct rsi_result handle_rsi_host_call(struct rec *rec,
-					struct rmi_rec_exit *rec_exit)
+void handle_rsi_host_call(struct rec *rec, struct rmi_rec_exit *rec_exit,
+			  struct rsi_result *res)
 {
-	struct rsi_result res = { 0 };
 	unsigned long ipa = rec->regs[1];
 
+	res->action = UPDATE_REC_RETURN_TO_REALM;
+
 	if (!ALIGNED(ipa, sizeof(struct rsi_host_call))) {
-		res.smc_res.x[0] = RSI_ERROR_INPUT;
-		return res;
+		res->smc_res.x[0] = RSI_ERROR_INPUT;
+		return;
 	}
 
 	if ((ipa / GRANULE_SIZE) !=
 		((ipa + sizeof(struct rsi_host_call) - 1UL) / GRANULE_SIZE)) {
-		res.smc_res.x[0] = RSI_ERROR_INPUT;
-		return res;
+		res->smc_res.x[0] = RSI_ERROR_INPUT;
+		return;
 	}
 
 	if (!addr_in_rec_par(rec, ipa)) {
-		res.smc_res.x[0] = RSI_ERROR_INPUT;
-		return res;
+		res->smc_res.x[0] = RSI_ERROR_INPUT;
+		return;
 	}
 
-	res.smc_res.x[0] = do_host_call(rec, rec_exit, NULL, &res.walk_result);
-
-	return res;
+	do_host_call(rec, rec_exit, NULL, res);
 }
 
 struct rsi_walk_result complete_rsi_host_call(struct rec *rec,
 					      struct rmi_rec_entry *rec_entry)
 {
-	struct rsi_walk_result res = { false, 0UL };
+	struct rsi_result res = { 0UL };
+	struct rsi_walk_result walk_res = { false, 0UL };
 
 	/*
 	 * Do the necessary to walk the S2 RTTs and copy args from NS Host
@@ -133,7 +142,12 @@
 	 * the RIPAS of IPA at that time). This is a situation which can be
 	 * controlled from Realm and Realm should avoid this.
 	 */
-	(void)do_host_call(rec, NULL, rec_entry, &res);
+	do_host_call(rec, NULL, rec_entry, &res);
 
-	return res;
+	if (res.action == STAGE_2_TRANSLATION_FAULT) {
+		walk_res.abort = true;
+		walk_res.rtt_level = res.rtt_level;
+	}
+
+	return walk_res;
 }