feat(el3-spmc): add support for FFA_CONSOLE_LOG

Add support for FFA_CONSOLE_LOG in EL3 SPMC,
Disallow forwarding FFA_CONSOLE_LOG across worlds.
Add support for FFA_CONSOLE_LOG in FFA_FEATURES.

Input parameters:
w0/x0 - FFA_CONSOLE_LOG_32/64
w1/x1 - Character count
w2/x2-w7/x7 - 24 or 48 characters depending upon whether a SMC32 or
SMC64 FID was used.

Output parameters in case of success:
w0/x0 - FFA_SUCCESS

Output parameters in case of error:
w0/x0 - FFA_ERROR
w2/x2 - NOT_SUPPORTED: ABI is not implemented
        INVALID_PARAMETERS: Parameters are incorrectly encoded

Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I004c043729e77d1b9aa396c42d25c73d9268169a
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
index 9ed6a8b..c5f6000 100644
--- a/include/services/ffa_svc.h
+++ b/include/services/ffa_svc.h
@@ -124,6 +124,8 @@
 #define FFA_FNUM_PARTITION_INFO_GET_REGS	U(0x8B)
 #define FFA_FNUM_EL3_INTR_HANDLE		U(0x8C)
 
+#define FFA_FNUM_CONSOLE_LOG			U(0x8A)
+
 /* FFA SMC32 FIDs */
 #define FFA_ERROR		FFA_FID(SMC_32, FFA_FNUM_ERROR)
 #define FFA_SUCCESS_SMC32	FFA_FID(SMC_32, FFA_FNUM_SUCCESS)
@@ -171,6 +173,7 @@
 #define FFA_EL3_INTR_HANDLE	FFA_FID(SMC_32, FFA_FNUM_EL3_INTR_HANDLE)
 #define FFA_MEM_PERM_GET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET)
 #define FFA_MEM_PERM_SET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET)
+#define FFA_CONSOLE_LOG_SMC32 FFA_FID(SMC_32, FFA_FNUM_CONSOLE_LOG)
 
 /* FFA SMC64 FIDs */
 #define FFA_ERROR_SMC64		FFA_FID(SMC_64, FFA_FNUM_ERROR)
@@ -191,6 +194,7 @@
 	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)
+#define FFA_CONSOLE_LOG_SMC64 FFA_FID(SMC_64, FFA_FNUM_CONSOLE_LOG)
 
 /*
  * FF-A partition properties values.
diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c
index 7978f08..9cfcd87 100644
--- a/services/std_svc/spm/el3_spmc/spmc_main.c
+++ b/services/std_svc/spm/el3_spmc/spmc_main.c
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2024, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <assert.h>
 #include <errno.h>
+#include <stdio.h>
 
 #include <arch_helpers.h>
 #include <bl31/bl31.h>
@@ -1290,6 +1291,8 @@
 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
 	case FFA_MEM_RELINQUISH:
 	case FFA_MSG_WAIT:
+	case FFA_CONSOLE_LOG_SMC32:
+	case FFA_CONSOLE_LOG_SMC64:
 
 		if (!secure_origin) {
 			return spmc_ffa_error_return(handle,
@@ -1476,6 +1479,61 @@
 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
 }
 
+static uint64_t spmc_ffa_console_log(uint32_t smc_fid,
+				     bool secure_origin,
+				     uint64_t x1,
+				     uint64_t x2,
+				     uint64_t x3,
+				     uint64_t x4,
+				     void *cookie,
+				     void *handle,
+				     uint64_t flags)
+{
+	char *chars;
+	size_t chars_max;
+	size_t chars_count = x1;
+
+	/* Does not support request from Nwd. */
+	if (!secure_origin) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+	}
+
+	assert(smc_fid == FFA_CONSOLE_LOG_SMC32 || smc_fid == FFA_CONSOLE_LOG_SMC64);
+	if (smc_fid == FFA_CONSOLE_LOG_SMC32) {
+		uint32_t registers[] = {
+			(uint32_t)x2,
+			(uint32_t)x3,
+			(uint32_t)x4,
+			(uint32_t)SMC_GET_GP(handle, CTX_GPREG_X5),
+			(uint32_t)SMC_GET_GP(handle, CTX_GPREG_X6),
+			(uint32_t)SMC_GET_GP(handle, CTX_GPREG_X7),
+		};
+		chars_max = ARRAY_SIZE(registers) * sizeof(uint32_t);
+		chars = (char *)registers;
+	} else {
+		uint64_t registers[] = {
+			x2,
+			x3,
+			x4,
+			SMC_GET_GP(handle, CTX_GPREG_X5),
+			SMC_GET_GP(handle, CTX_GPREG_X6),
+			SMC_GET_GP(handle, CTX_GPREG_X7),
+		};
+		chars_max = ARRAY_SIZE(registers) * sizeof(uint64_t);
+		chars = (char *)registers;
+	}
+
+	if ((chars_count == 0) || (chars_count > chars_max)) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	for (size_t i = 0; (i < chars_count) && (chars[i] != '\0'); i++) {
+		putchar(chars[i]);
+	}
+
+	SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
 /*
  * Perform initial validation on the provided secondary entry point.
  * For now ensure it does not lie within the BL31 Image or the SP's
@@ -2365,7 +2423,11 @@
 
 	case FFA_MEM_RECLAIM:
 		return spmc_ffa_mem_reclaim(smc_fid, secure_origin, x1, x2, x3,
-					    x4, cookie, handle, flags);
+						x4, cookie, handle, flags);
+	case FFA_CONSOLE_LOG_SMC32:
+	case FFA_CONSOLE_LOG_SMC64:
+		return spmc_ffa_console_log(smc_fid, secure_origin, x1, x2, x3,
+						x4, cookie, handle, flags);
 
 	case FFA_MEM_PERM_GET:
 		return ffa_mem_perm_get_handler(smc_fid, secure_origin, x1, x2,
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 066571e..1d0bd00 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -1279,6 +1279,12 @@
 					handle, flags);
 		break; /* Not reached */
 #endif
+	case FFA_CONSOLE_LOG_SMC32:
+	case FFA_CONSOLE_LOG_SMC64:
+		/* This interface must not be forwarded to other worlds. */
+		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+		break; /* not reached */
+
 	case FFA_EL3_INTR_HANDLE:
 		if (secure_origin) {
 			return spmd_handle_group0_intr_swd(handle);