feat: add implementation of `memcpy_trapped`

Add implementation of `memcpy_trapped` which is capable of returning
error in case any of the memory accesses from source and destination
result in a data abort.

The `sync_current_exception` was refactored such that it can infer a
GPF, and in the exact str/ldr locations of the `memcpy_trapped`.

Prepare the `sync_current_exception` handler to process the GPF.
It shall be able to change the `ELR_EL2`, and return false
signaling that `ELR_EL2` shall not be restored from stack.

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: Id268140441a16b346b06a4891f97e69c0d1b8e6e
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 47e1a96..976fd09 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -11,6 +11,7 @@
 #include "hf/arch/barriers.h"
 #include "hf/arch/gicv3.h"
 #include "hf/arch/init.h"
+#include "hf/arch/memcpy_trapped.h"
 #include "hf/arch/mmu.h"
 #include "hf/arch/plat/ffa.h"
 #include "hf/arch/plat/smc.h"
@@ -232,7 +233,12 @@
 	panic("SError from current exception level.");
 }
 
-noreturn void sync_current_exception_noreturn(uintreg_t elr, uintreg_t spsr)
+/**
+ * Returns true if ELR_EL2 is not to be restored from stack.
+ * Currently function doesn't return false, as for all other cases
+ * panics.
+ */
+bool sync_current_exception(uintreg_t elr, uintreg_t spsr)
 {
 	uintreg_t esr = read_msr(esr_el2);
 	uintreg_t ec = GET_ESR_EC(esr);
@@ -240,21 +246,53 @@
 	(void)spsr;
 
 	switch (ec) {
-	case EC_DATA_ABORT_SAME_EL:
+	case EC_DATA_ABORT_SAME_EL: {
+		uint64_t iss = GET_ESR_ISS(esr);
+		uint64_t dfsc = GET_ESR_ISS_DFSC(iss);
+		uint64_t far = read_msr(far_el2);
+
+		/* Handle Granule Protection Fault. */
+		if (is_arch_feat_rme_supported() && dfsc == DFSC_GPF) {
+			dlog_verbose(
+				"Granule Protection Fault: esr=%#x, ec=%#x, "
+				"far=%#x, elr=%#x\n",
+				esr, ec, far, elr);
+
+			/*
+			 * Change ELR_EL2 only if failed whilst either
+			 * reading or writing within 'memcpy_trapped'.
+			 */
+			if (elr == (uintptr_t)memcpy_trapped_read ||
+			    elr == (uintptr_t)memcpy_trapped_write) {
+				dlog_verbose(
+					"GPF due to data abort on %s.\n",
+					(elr == (uintptr_t)memcpy_trapped_read)
+						? "read"
+						: "write");
+
+				/*
+				 * Update the ELR_EL2 with the return
+				 * address, to return error from the
+				 * call to 'memcpy_trapped'.
+				 */
+				write_msr(ELR_EL2, memcpy_trapped_aborted);
+				return true;
+			}
+		}
+
 		if (!(esr & (1U << 10))) { /* Check FnV bit. */
 			dlog_error(
 				"Data abort: pc=%#x, esr=%#x, ec=%#x, "
 				"far=%#x\n",
-				elr, esr, ec, read_msr(far_el2));
+				elr, esr, ec, far);
+
 		} else {
 			dlog_error(
 				"Data abort: pc=%#x, esr=%#x, ec=%#x, "
 				"far=invalid\n",
 				elr, esr, ec);
 		}
-
-		break;
-
+	} break;
 	default:
 		dlog_error(
 			"Unknown current sync exception pc=%#x, esr=%#x, "