test(realm): add plane PSI interface

Add Plane service routine interface.
Aux plane can communicate with primary plane using PSI
PSI uses hvc conduit from aux plane.
Add initial printf support for planes

Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I484cbd32791970c6e22c5d63e13b43807f4f3c06
diff --git a/realm/aarch64/realm_entrypoint.S b/realm/aarch64/realm_entrypoint.S
index 7e535bb..1c20dca 100644
--- a/realm/aarch64/realm_entrypoint.S
+++ b/realm/aarch64/realm_entrypoint.S
@@ -81,6 +81,8 @@
 	 */
 	adr	x0, cold_boot_flag
 	str	xzr, [x0]
+
+	bl	realm_plane_init
 loop:
 	/* And jump to the C entrypoint */
 	bl	realm_payload_main
@@ -92,6 +94,7 @@
 #if ENABLE_PAUTH
 	bl	pauth_init_enable
 #endif
+	bl	realm_plane_init
 	mov	x0, x20
 	b	realm_secondary_entrypoint
 endfunc realm_entrypoint
diff --git a/realm/include/realm_helpers.h b/realm/include/realm_helpers.h
index a9b2f7c..9214564 100644
--- a/realm/include/realm_helpers.h
+++ b/realm/include/realm_helpers.h
@@ -8,6 +8,8 @@
 #ifndef REALM_HELPERS_H
 #define REALM_HELPERS_H
 
+#include <realm_rsi.h>
+
 /* Generate 64-bit random number */
 unsigned long long realm_rand64(void);
 /*
@@ -21,6 +23,15 @@
 bool realm_plane_enter(u_register_t plane_index, u_register_t perm_index,
 		u_register_t base, u_register_t flags, rsi_plane_run *run);
 
+/* This function will call the Host to request IPA of the NS shared buffer */
+u_register_t realm_get_ns_buffer(void);
+
+/* This function will return plane index of current plane */
+unsigned int realm_get_my_plane_num(void);
+
+/** This function will return true for primary plane false for aux plane */
+bool realm_is_plane0(void);
+
 /* Function for initializing planes, called at Boot */
 void realm_plane_init(void);
 
diff --git a/realm/include/realm_psi.h b/realm/include/realm_psi.h
new file mode 100644
index 0000000..bab2896
--- /dev/null
+++ b/realm/include/realm_psi.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef REALM_PSI_H
+#define REALM_PSI_H
+
+#include <stdint.h>
+#include <realm_rsi.h>
+
+/*
+ * Plane Service Interface
+ * ABIs are designed to be used by auxillary planes to interact with primary plane.
+ * PSI calls uses HVC conduit which causes Plane exit to P0
+ * PSI commands and Planes shared buffer can be used for communication.
+ */
+#define PSI_RETURN_TO_P0	1U
+#define PSI_RETURN_TO_PN	2U
+
+/* PSI Commands to return back to P0 */
+#define PSI_P0_CALL			RSI_HOST_CALL
+#define PSI_REALM_CONFIG		RSI_REALM_CONFIG
+#define PSI_CALL_EXIT_PRINT_CMD		HOST_CALL_EXIT_PRINT_CMD
+#define PSI_CALL_EXIT_SUCCESS_CMD	HOST_CALL_EXIT_SUCCESS_CMD
+#define PSI_CALL_EXIT_FAILED_CMD	HOST_CALL_EXIT_FAILED_CMD
+#define PSI_CALL_GET_PLANE_ID_CMD	HOST_CALL_GET_PLANE_ID_CMD
+#define PSI_CALL_GET_SHARED_BUFF_CMD	HOST_CALL_GET_SHARED_BUFF_CMD
+
+/* Exit back to Plane 0 */
+void psi_exit_to_plane0(u_register_t psi_cmd,
+			u_register_t arg1,
+			u_register_t arg2,
+			u_register_t arg3,
+			u_register_t arg4,
+			u_register_t arg5,
+			u_register_t arg6,
+			u_register_t arg7);
+
+/* Request plane_id from P0 */
+u_register_t psi_get_plane_id(void);
+
+#endif /* REALM_PSI_H */
diff --git a/realm/include/realm_rsi.h b/realm/include/realm_rsi.h
index 33e8fcf..e72a769 100644
--- a/realm/include/realm_rsi.h
+++ b/realm/include/realm_rsi.h
@@ -321,9 +321,6 @@
 /* This function return RSI_ABI_VERSION */
 u_register_t rsi_get_version(u_register_t req_ver);
 
-/* This function will call the Host to request IPA of the NS shared buffer */
-u_register_t rsi_get_ns_buffer(void);
-
 /* This function will initialize the attestation context */
 u_register_t rsi_attest_token_init(u_register_t challenge_0,
 				   u_register_t challenge_1,
@@ -342,7 +339,7 @@
 					u_register_t *bytes_copied);
 
 /* This function call Host and request to exit Realm with proper exit code */
-void rsi_exit_to_host(enum host_call_cmd exit_code);
+u_register_t rsi_exit_to_host(enum host_call_cmd exit_code);
 
 /* Function to get Realm configuration. See RSI_REALM_CONFIG */
 u_register_t rsi_realm_config(struct rsi_realm_config *s);
diff --git a/realm/realm.mk b/realm/realm.mk
index f59387c..7d21ed5 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -37,6 +37,7 @@
 	realm_plane.c							\
 	realm_pmuv3.c							\
 	realm_psci.c							\
+	realm_psi.c							\
 	realm_rsi.c							\
 	realm_shared_data.c						\
 	realm_simd.c							\
@@ -45,6 +46,7 @@
 REALM_SOURCES += lib/${ARCH}/cache_helpers.S				\
 	lib/${ARCH}/misc_helpers.S					\
 	lib/smc/${ARCH}/asm_smc.S					\
+	lib/smc/${ARCH}/hvc.c						\
 	lib/smc/${ARCH}/smc.c						\
 	lib/exceptions/${ARCH}/serror.c					\
 	lib/exceptions/${ARCH}/sync.c					\
diff --git a/realm/realm_debug.c b/realm/realm_debug.c
index 1c4ee03..6bf8adf 100644
--- a/realm/realm_debug.c
+++ b/realm/realm_debug.c
@@ -11,6 +11,8 @@
 
 #include <arch_helpers.h>
 #include <host_shared_data.h>
+#include <realm_helpers.h>
+#include <realm_psi.h>
 #include <realm_rsi.h>
 
 /*
@@ -23,6 +25,7 @@
 	host_shared_data_t *guest_shared_data = realm_get_my_shared_structure();
 	char *log_buffer = (char *)guest_shared_data->log_buffer;
 	va_list args;
+	u_register_t ret;
 
 	va_start(args, fmt);
 	if (strnlen((const char *)log_buffer, MAX_BUF_SIZE) == MAX_BUF_SIZE) {
@@ -32,7 +35,15 @@
 			strnlen((const char *)log_buffer, MAX_BUF_SIZE),
 			MAX_BUF_SIZE, fmt, args);
 	va_end(args);
-	rsi_exit_to_host(HOST_CALL_EXIT_PRINT_CMD);
+	ret = rsi_exit_to_host(HOST_CALL_EXIT_PRINT_CMD);
+
+	/*
+	 * Retry with PSI call for secondary planes
+	 * Note - RSI_HOST_CALL will fail if test in P0 sets trap_hc flag in plane_enter
+	 */
+	if ((ret != RSI_SUCCESS && !realm_is_plane0())) {
+		psi_exit_to_plane0(PSI_CALL_EXIT_PRINT_CMD, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+	}
 }
 
 void __attribute__((__noreturn__)) do_panic(const char *file, int line)
diff --git a/realm/realm_helpers.c b/realm/realm_helpers.c
index 6a3c57d..bf47efc 100644
--- a/realm/realm_helpers.c
+++ b/realm/realm_helpers.c
@@ -5,6 +5,10 @@
  */
 
 #include <stdlib.h>
+#include <realm_helpers.h>
+#include <realm_psi.h>
+#include <realm_rsi.h>
+#include <smccc.h>
 
 /* Generate 64-bit random number */
 unsigned long long realm_rand64(void)
@@ -12,3 +16,26 @@
 	return ((unsigned long long)rand() << 32) | rand();
 }
 
+/* This function will call the Host to request IPA of the NS shared buffer */
+u_register_t realm_get_ns_buffer(void)
+{
+	smc_ret_values res = {};
+	struct rsi_host_call host_cal __aligned(sizeof(struct rsi_host_call));
+
+	host_cal.imm = HOST_CALL_GET_SHARED_BUFF_CMD;
+	res = tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
+		0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
+
+	if (res.ret0 != RSI_SUCCESS) {
+		/* retry with PSI */
+		hvc_ret_values ret = tftf_hvc(&(hvc_args) {PSI_CALL_GET_SHARED_BUFF_CMD, 0UL, 0UL,
+			0UL, 0UL, 0UL, 0UL, 0UL});
+
+		if (ret.ret0 != RSI_SUCCESS) {
+			return 0U;
+		}
+		return ret.ret1;
+	}
+
+	return host_cal.gprs[0];
+}
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index 3339b9a..eb4c9aa 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -14,6 +14,8 @@
 #include <host_shared_data.h>
 #include <pauth.h>
 #include "realm_def.h"
+#include <realm_helpers.h>
+#include <realm_psi.h>
 #include <realm_rsi.h>
 #include <realm_tests.h>
 #include <serror.h>
@@ -184,18 +186,20 @@
 
 static bool realm_exception_handler(void)
 {
-	u_register_t base, far, esr;
+	u_register_t base, far, esr, elr;
 
 	base = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
 	far = read_far_el1();
 	esr = read_esr_el1();
+	elr = read_elr_el1();
 
 	if (far == base) {
 		/* Return ESR to Host */
 		realm_shared_data_set_my_realm_val(HOST_ARG2_INDEX, esr);
 		rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
 	}
-	realm_printf("Realm Abort fail incorrect FAR=0x%lx ESR=0x%lx\n", far, esr);
+	realm_printf("Realm Abort fail incorrect FAR=0x%lx ESR=0x%lx ELR=0x%lx\n",
+			far, esr, elr);
 	rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
 
 	/* Should not return */
@@ -266,7 +270,7 @@
 	/* No serror handler registered by default */
 	unregister_custom_serror_handler();
 
-	realm_set_shared_structure((host_shared_data_t *)rsi_get_ns_buffer());
+	realm_set_shared_structure((host_shared_data_t *)realm_get_ns_buffer());
 
 	if (realm_get_my_shared_structure() != NULL) {
 		uint8_t cmd = realm_shared_data_get_my_realm_cmd();
@@ -381,8 +385,18 @@
 	}
 
 	if (test_succeed) {
-		rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+		if (realm_is_plane0()) {
+			rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+		} else {
+			psi_exit_to_plane0(PSI_CALL_EXIT_SUCCESS_CMD,
+					0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+		}
 	} else {
-		rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+		if (realm_is_plane0()) {
+			rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+		} else {
+			psi_exit_to_plane0(PSI_CALL_EXIT_FAILED_CMD,
+					0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
+		}
 	}
 }
diff --git a/realm/realm_plane.c b/realm/realm_plane.c
index ef1e0ab..7affc15 100644
--- a/realm/realm_plane.c
+++ b/realm/realm_plane.c
@@ -11,10 +11,22 @@
 #include <debug.h>
 
 #include <host_realm_helper.h>
+#include <realm_psi.h>
 #include <realm_rsi.h>
 #include <sync.h>
 
-bool is_plane0;
+static bool is_plane0;
+static unsigned int plane_num;
+
+bool realm_is_plane0(void)
+{
+	return is_plane0;
+}
+
+unsigned int realm_get_my_plane_num(void)
+{
+	return plane_num;
+}
 
 void realm_plane_init(void)
 {
@@ -23,8 +35,10 @@
 	ret = rsi_get_version(RSI_ABI_VERSION_VAL);
 	if (ret == RSI_ERROR_STATE) {
 		is_plane0 = false;
+		plane_num = (unsigned int)psi_get_plane_id();
 	} else {
 		is_plane0 = true;
+		plane_num = PRIMARY_PLANE_ID;
 	}
 }
 
@@ -37,12 +51,28 @@
 	run->enter.pc = run->exit.elr;
 }
 
+static u_register_t realm_exit_to_host_as_plane_n(enum host_call_cmd exit_code,
+		u_register_t plane_num)
+{
+	struct rsi_host_call host_cal __aligned(sizeof(struct rsi_host_call));
+	smc_ret_values res = {};
+
+	assert(realm_is_p0());
+	host_cal.imm = exit_code;
+	host_cal.gprs[0] = plane_num;
+	host_cal.gprs[1] = read_mpidr_el1();
+	res = tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
+		0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
+	return res.ret0;
+}
+
 /* return true to re-enter PlaneN, false to exit to P0 */
 static bool handle_plane_exit(u_register_t plane_index,
 		u_register_t perm_index,
 		rsi_plane_run *run)
 {
 	u_register_t ec = EC_BITS(run->exit.esr);
+	u_register_t ret;
 
 	/* Disallow SMC from Plane N */
 	if (ec == EC_AARCH64_SMC) {
@@ -50,6 +80,31 @@
 		run->enter.gprs[0] = RSI_ERROR_STATE;
 		return true;
 	}
+
+	/* Handle PSI HVC call from Plane N */
+	if (ec == EC_AARCH64_HVC) {
+		u_register_t hvc_id = run->exit.gprs[0];
+
+		restore_plane_context(run);
+		switch (hvc_id) {
+		case PSI_CALL_GET_SHARED_BUFF_CMD:
+			run->enter.gprs[0] = RSI_SUCCESS;
+			run->enter.gprs[1] = (u_register_t)realm_get_my_shared_structure();
+			return true;
+		case PSI_CALL_GET_PLANE_ID_CMD:
+			run->enter.gprs[0] = RSI_SUCCESS;
+			run->enter.gprs[1] = plane_index;
+			return true;
+		case PSI_CALL_EXIT_PRINT_CMD:
+			/* exit to host to flush buffer, then return to PN */
+			ret = realm_exit_to_host_as_plane_n(HOST_CALL_EXIT_PRINT_CMD, plane_index);
+			run->enter.gprs[0] = ret;
+			return true;
+		case PSI_P0_CALL:
+		default:
+			return false;
+		}
+	}
 	return false;
 }
 
diff --git a/realm/realm_psi.c b/realm/realm_psi.c
new file mode 100644
index 0000000..9939d7e
--- /dev/null
+++ b/realm/realm_psi.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <host_realm_rmi.h>
+#include <realm_helpers.h>
+#include <realm_psi.h>
+#include <realm_rsi.h>
+#include <smccc.h>
+
+void psi_exit_to_plane0(u_register_t psi_cmd,
+			u_register_t arg1,
+			u_register_t arg2,
+			u_register_t arg3,
+			u_register_t arg4,
+			u_register_t arg5,
+			u_register_t arg6,
+			u_register_t arg7)
+{
+	if (realm_is_plane0()) {
+		return;
+	}
+	tftf_hvc(&(hvc_args) {psi_cmd, arg1, arg2, arg3, arg4,
+			arg5, arg6, arg7});
+}
+
+u_register_t psi_get_plane_id(void)
+{
+	hvc_ret_values res = tftf_hvc(&(hvc_args) {PSI_CALL_GET_PLANE_ID_CMD, 0UL, 0UL,
+			0UL, 0UL, 0UL, 0UL, 0UL});
+
+	if (res.ret0 != RSI_SUCCESS) {
+		return (u_register_t)-1;
+	}
+	return res.ret1;
+}
+
diff --git a/realm/realm_rsi.c b/realm/realm_rsi.c
index 1c6fc8e..b2505cc 100644
--- a/realm/realm_rsi.c
+++ b/realm/realm_rsi.c
@@ -8,6 +8,7 @@
 
 #include <host_realm_rmi.h>
 #include <lib/aarch64/arch_features.h>
+#include <realm_helpers.h>
 #include <realm_rsi.h>
 #include <smccc.h>
 
@@ -31,30 +32,18 @@
 	return res.ret1;
 }
 
-/* This function will call the Host to request IPA of the NS shared buffer */
-u_register_t rsi_get_ns_buffer(void)
-{
-	smc_ret_values res = {};
-	struct rsi_host_call host_cal __aligned(sizeof(struct rsi_host_call));
-
-	host_cal.imm = HOST_CALL_GET_SHARED_BUFF_CMD;
-	res = tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
-		0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
-	if (res.ret0 != RSI_SUCCESS) {
-		return 0U;
-	}
-	return host_cal.gprs[0];
-}
-
 /* This function call Host and request to exit Realm with proper exit code */
-void rsi_exit_to_host(enum host_call_cmd exit_code)
+u_register_t rsi_exit_to_host(enum host_call_cmd exit_code)
 {
 	struct rsi_host_call host_cal __aligned(sizeof(struct rsi_host_call));
+	smc_ret_values res = {};
 
 	host_cal.imm = exit_code;
-	host_cal.gprs[0] = read_mpidr_el1();
-	tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
+	host_cal.gprs[0] = realm_get_my_plane_num();
+	host_cal.gprs[1] = read_mpidr_el1();
+	res = tftf_smc(&(smc_args) {RSI_HOST_CALL, (u_register_t)&host_cal,
 		0UL, 0UL, 0UL, 0UL, 0UL, 0UL});
+	return res.ret0;
 }
 
 /* This function will exit to the Host to request RIPAS CHANGE of IPA range */
diff --git a/realm/realm_shared_data.c b/realm/realm_shared_data.c
index 2825796..db66520 100644
--- a/realm/realm_shared_data.c
+++ b/realm/realm_shared_data.c
@@ -59,4 +59,3 @@
 	assert(index < MAX_DATA_SIZE);
 	guest_shared_data[REC_IDX(read_mpidr_el1())].realm_out_val[index] = val;
 }
-