feat(spmd): introduce FFA_PARTITION_INFO_GET_REGS

Add code in SPMD to forward calls to FFA_PARTITION_INFO_GET_REGS. This
is a new ABI that allows getting partition information without the need
for rx/tx buffer, that helps in situations where having an rx/tx buffer
mapped and available is difficult (ex. uefi runtime services).
Currently, the spmc at el3 does not support this new ABI.
The new ABI uses registers x8-x17 to return partition information so
changes are made to ensure those registers are passed through to the
SPMC and restored on the return path.

Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: I1fe5956763e054e4f8d62292fc1247e7120bb5a4
diff --git a/include/arch/aarch64/smccc_helpers.h b/include/arch/aarch64/smccc_helpers.h
index 920f294..950a811 100644
--- a/include/arch/aarch64/smccc_helpers.h
+++ b/include/arch/aarch64/smccc_helpers.h
@@ -75,6 +75,24 @@
 #define SMC_SET_GP(_h, _g, _v)					\
 	write_ctx_reg((get_gpregs_ctx(_h)), (_g), (_v))
 
+
+/* Useful for SMCCCv1.2 */
+#define SMC_RET18(_h, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7, _x8, _x9, \
+		_x10, _x11, _x12, _x13, _x14, _x15, _x16, _x17) {	\
+	SMC_SET_GP(_h, CTX_GPREG_X8, _x8);				\
+	SMC_SET_GP(_h, CTX_GPREG_X9, _x9);				\
+	SMC_SET_GP(_h, CTX_GPREG_X10, _x10);				\
+	SMC_SET_GP(_h, CTX_GPREG_X11, _x11);				\
+	SMC_SET_GP(_h, CTX_GPREG_X12, _x12);				\
+	SMC_SET_GP(_h, CTX_GPREG_X13, _x13);				\
+	SMC_SET_GP(_h, CTX_GPREG_X14, _x14);				\
+	SMC_SET_GP(_h, CTX_GPREG_X15, _x15);				\
+	SMC_SET_GP(_h, CTX_GPREG_X16, _x16);				\
+	SMC_SET_GP(_h, CTX_GPREG_X17, _x17);				\
+	SMC_RET8(_h, (_x0), (_x1), (_x2), (_x3), (_x4), (_x5), (_x6),	\
+		(_x7));							\
+}
+
 /*
  * Convenience macros to access EL3 context registers using handle provided to
  * SMC handler. These take the offset values defined in context.h
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
index da016fd..8bc911a 100644
--- a/include/services/ffa_svc.h
+++ b/include/services/ffa_svc.h
@@ -24,7 +24,7 @@
 
 /* The macros below are used to identify FFA calls from the SMC function ID */
 #define FFA_FNUM_MIN_VALUE	U(0x60)
-#define FFA_FNUM_MAX_VALUE	U(0x87)
+#define FFA_FNUM_MAX_VALUE	U(0x8B)
 #define is_ffa_fid(fid) __extension__ ({		\
 	__typeof__(fid) _fid = (fid);			\
 	((GET_SMC_NUM(_fid) >= FFA_FNUM_MIN_VALUE) &&	\
@@ -117,6 +117,7 @@
 #define FFA_FNUM_SPM_ID_GET			U(0x85)
 #define FFA_FNUM_MSG_SEND2			U(0x86)
 #define FFA_FNUM_SECONDARY_EP_REGISTER		U(0x87)
+#define FFA_FNUM_PARTITION_INFO_GET_REGS	U(0x8B)
 
 /* FFA SMC32 FIDs */
 #define FFA_ERROR		FFA_FID(SMC_32, FFA_FNUM_ERROR)
@@ -180,6 +181,8 @@
 	FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
 #define FFA_NOTIFICATION_INFO_GET_SMC64 \
 	FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
+#define FFA_PARTITION_INFO_GET_REGS_SMC64 \
+	FFA_FID(SMC_64, FFA_FNUM_PARTITION_INFO_GET_REGS)
 
 /*
  * FF-A partition properties values.
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index dde1622..3c207ad 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -581,10 +581,40 @@
 #endif
 	cm_set_next_eret_context(secure_state_out);
 
+#if SPMD_SPM_AT_SEL2
+	/*
+	 * If SPMC is at SEL2, save additional registers x8-x17, which may
+	 * be used in FF-A calls such as FFA_PARTITION_INFO_GET_REGS.
+	 * Note that technically, all SPMCs can support this, but this code is
+	 * under ifdef to minimize breakage in case other SPMCs do not save
+	 * and restore x8-x17.
+	 * We also need to pass through these registers since not all FF-A ABIs
+	 * modify x8-x17, in which case, SMCCC requires that these registers be
+	 * preserved, so the SPMD passes through these registers and expects the
+	 * SPMC to save and restore (potentially also modify) them.
+	 */
+	SMC_RET18(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
+			SMC_GET_GP(handle, CTX_GPREG_X5),
+			SMC_GET_GP(handle, CTX_GPREG_X6),
+			SMC_GET_GP(handle, CTX_GPREG_X7),
+			SMC_GET_GP(handle, CTX_GPREG_X8),
+			SMC_GET_GP(handle, CTX_GPREG_X9),
+			SMC_GET_GP(handle, CTX_GPREG_X10),
+			SMC_GET_GP(handle, CTX_GPREG_X11),
+			SMC_GET_GP(handle, CTX_GPREG_X12),
+			SMC_GET_GP(handle, CTX_GPREG_X13),
+			SMC_GET_GP(handle, CTX_GPREG_X14),
+			SMC_GET_GP(handle, CTX_GPREG_X15),
+			SMC_GET_GP(handle, CTX_GPREG_X16),
+			SMC_GET_GP(handle, CTX_GPREG_X17)
+			);
+
+#else
 	SMC_RET8(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
 			SMC_GET_GP(handle, CTX_GPREG_X5),
 			SMC_GET_GP(handle, CTX_GPREG_X6),
 			SMC_GET_GP(handle, CTX_GPREG_X7));
+#endif
 }
 
 /*******************************************************************************
@@ -1042,7 +1072,23 @@
 			return spmd_ffa_error_return(handle, FFA_ERROR_DENIED);
 		}
 		break; /* Not reached */
+#if MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED
+	case FFA_PARTITION_INFO_GET_REGS_SMC64:
+		if (secure_origin) {
+			/* TODO: Future patches to enable support for this */
+			return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+		}
 
+		/* Call only supported with SMCCC 1.2+ */
+		if (MAKE_SMCCC_VERSION(SMCCC_MAJOR_VERSION, SMCCC_MINOR_VERSION) < 0x10002) {
+			return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+		}
+
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, cookie,
+					handle, flags);
+		break; /* Not reached */
+#endif
 	default:
 		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
 		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);