cactus: select different stdout device at runtime

cactus is used as both primary and secondary VM and for debug logging
primary VM can access to UART while secodary VM's use hypervisor call to
SPM.

Based on VM id it will be decided whether to use UART or hypervisor call
for debug logging.

Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
Change-Id: I97786b893c0156815969692582b4de62c1b568fd
diff --git a/spm/cactus/cactus.h b/spm/cactus/cactus.h
index 0b06eb2..cbf2dcb 100644
--- a/spm/cactus/cactus.h
+++ b/spm/cactus/cactus.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,4 +26,11 @@
 #define CACTUS_BSS_START	((uintptr_t)&__BSS_START__)
 #define CACTUS_BSS_END		((uintptr_t)&__BSS_END__)
 
+enum stdout_route {
+	PL011_AS_STDOUT = 0,
+	HVC_CALL_AS_STDOUT,
+};
+
+void set_putc_impl(enum stdout_route);
+
 #endif /* __CACTUS_H__ */
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index ccb85b9..a32d3d3 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -24,6 +24,7 @@
 CACTUS_SOURCES	:=					\
 	$(addprefix spm/cactus/,			\
 		aarch64/cactus_entrypoint.S		\
+		cactus_debug.c				\
 		cactus_main.c				\
 	)						\
 	$(addprefix spm/common/,			\
@@ -37,7 +38,6 @@
 	tftf/framework/${ARCH}/asm_debug.S
 
 CACTUS_SOURCES	+= 	drivers/arm/pl011/${ARCH}/pl011_console.S	\
-			drivers/console/console.c			\
 			lib/${ARCH}/cache_helpers.S			\
 			lib/${ARCH}/misc_helpers.S			\
 			lib/smc/${ARCH}/asm_smc.S			\
diff --git a/spm/cactus/cactus_debug.c b/spm/cactus/cactus_debug.c
new file mode 100644
index 0000000..cce0973
--- /dev/null
+++ b/spm/cactus/cactus_debug.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+
+#include "cactus.h"
+#include "spci_helpers.h"
+
+static int (*putc_impl)(int);
+
+static int putc_hypcall(int c)
+{
+	spm_debug_log((char)c);
+
+	return c;
+}
+
+static int putc_uart(int c)
+{
+	console_pl011_putc(c);
+
+	return c;
+}
+
+void set_putc_impl(enum stdout_route route)
+{
+	switch (route) {
+
+	case HVC_CALL_AS_STDOUT:
+		putc_impl = putc_hypcall;
+		return;
+
+	case PL011_AS_STDOUT:
+	default:
+		break;
+	}
+
+	putc_impl = putc_uart;
+}
+
+int console_putc(int c)
+{
+	if (!putc_impl) {
+		return -1;
+	}
+
+	return putc_impl(c);
+}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 1b641af..be137ad 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -15,110 +15,16 @@
 #include <plat_arm.h>
 #include <plat/common/platform.h>
 #include <platform_def.h>
-#include <spci_svc.h>
 #include <std_svc.h>
 
 #include "cactus.h"
 #include "cactus_def.h"
-
-#include "tftf_lib.h"
-
-#define SPM_VM_ID_FIRST			(1)
-
-#define SPM_VM_GET_COUNT		(0xFF01)
-#define SPM_VCPU_GET_COUNT		(0xFF02)
-#define SPM_DEBUG_LOG			(0xBD000000)
-
-/* Hypervisor ID at physical SPCI instance */
-#define HYP_ID		(0)
-
-/* By convention, SP IDs (as opposed to VM IDs) have bit 15 set */
-#define SP_ID(x)	(x | (1 << 15))
-
-typedef unsigned short spci_vm_id_t;
-typedef unsigned short spci_vm_count_t;
-typedef unsigned short spci_vcpu_count_t;
+#include "spci_helpers.h"
 
 /* Host machine information injected by the build system in the ELF file. */
 extern const char build_message[];
 extern const char version_string[];
 
-static spci_vcpu_count_t spm_vcpu_get_count(spci_vm_id_t vm_id)
-{
-	hvc_args args = {
-		.fid = SPM_VCPU_GET_COUNT,
-		.arg1 = vm_id
-	};
-
-	hvc_ret_values ret = tftf_hvc(&args);
-
-	return ret.ret0;
-}
-
-static spci_vm_count_t spm_vm_get_count(void)
-{
-	hvc_args args = {
-		.fid = SPM_VM_GET_COUNT
-	};
-
-	hvc_ret_values ret = tftf_hvc(&args);
-
-	return ret.ret0;
-}
-
-static void spm_debug_log(char c)
-{
-	hvc_args args = {
-		.fid = SPM_DEBUG_LOG,
-		.arg1 = c
-	};
-
-	(void)tftf_hvc(&args);
-}
-
-static smc_ret_values spci_id_get(void)
-{
-	smc_args args = {
-		.fid = SPCI_ID_GET
-	};
-
-	return tftf_smc(&args);
-}
-
-static smc_ret_values spci_msg_wait(void)
-{
-	smc_args args = {
-		.fid = SPCI_MSG_WAIT
-	};
-
-	return tftf_smc(&args);
-}
-
-/* Send response through registers using direct messaging */
-static smc_ret_values spci_msg_send_direct_resp(spci_vm_id_t sender_vm_id,
-					 spci_vm_id_t target_vm_id,
-					 uint32_t message)
-{
-	smc_args args = {
-		.fid = SPCI_MSG_SEND_DIRECT_RESP_SMC32,
-		.arg1 = ((uint32_t)sender_vm_id << 16) | target_vm_id,
-		.arg3 = message
-	};
-
-	return tftf_smc(&args);
-}
-
-static smc_ret_values spci_error(int32_t error_code)
-{
-	smc_args args = {
-		.fid = SPCI_ERROR,
-		.arg1 = 0,
-		.arg2 = error_code
-	};
-
-	return tftf_smc(&args);
-}
-
 /*
  *
  * Message loop function
@@ -249,36 +155,32 @@
 	}
 
 	spci_vm_id_t spci_id = spci_id_ret.ret2 & 0xffff;
-	if (spci_id > SPM_VM_ID_FIRST) {
-		/* Indicate secondary VM start through debug log hypercall */
-		spm_debug_log('2');
-		spm_debug_log('N');
-		spm_debug_log('D');
-		spm_debug_log('\n');
 
-		/* Run straight to the message loop */
-		message_loop(spci_id);
+	if (spci_id == SPM_VM_ID_FIRST) {
+		console_init(PL011_UART2_BASE,
+			PL011_UART2_CLK_IN_HZ,
+			PL011_BAUDRATE);
+
+		set_putc_impl(PL011_AS_STDOUT);
+
+		NOTICE("Booting Primary Cactus Secure Partition\n%s\n%s\n",
+			build_message, version_string);
+
+		cactus_print_memory_layout();
+
+		NOTICE("SPCI id: %u\n", spci_id); /* Expect VM id 1 */
+
+		/* Get number of VMs */
+		NOTICE("VM count: %u\n", spm_vm_get_count());
+
+		/* Get virtual CPU count for current VM */
+		NOTICE("vCPU count: %u\n", spm_vcpu_get_count(spci_id));
+	} else {
+		set_putc_impl(HVC_CALL_AS_STDOUT);
+
+		NOTICE("Booting Secondary Cactus Secure Partition\n%s\n%s\n",
+			build_message, version_string);
 	}
-
-	/* Next initialization steps only performed by primary VM */
-
-	console_init(PL011_UART2_BASE,
-		     PL011_UART2_CLK_IN_HZ,
-		     PL011_BAUDRATE);
-
-	NOTICE("Booting Cactus Secure Partition\n%s\n%s\n",
-	       build_message, version_string);
-
-	cactus_print_memory_layout();
-
-	NOTICE("SPCI id: %u\n", spci_id); /* Expect VM id 1 */
-
-	/* Get number of VMs */
-	NOTICE("VM count: %u\n", spm_vm_get_count());
-
-	/* Get virtual CPU count for current VM */
-	NOTICE("vCPU count: %u\n", spm_vcpu_get_count(spci_id));
-
 	/* End up to message loop */
 	message_loop(spci_id);
 
diff --git a/spm/cactus/spci_helpers.h b/spm/cactus/spci_helpers.h
new file mode 100644
index 0000000..189df9a
--- /dev/null
+++ b/spm/cactus/spci_helpers.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SPCI_HELPERS_H__
+#define __SPCI_HELPERS_H__
+
+
+#include <spci_svc.h>
+#include "tftf_lib.h"
+
+#define SPM_VM_ID_FIRST                 (1)
+
+#define SPM_VM_GET_COUNT                (0xFF01)
+#define SPM_VCPU_GET_COUNT              (0xFF02)
+#define SPM_DEBUG_LOG                   (0xBD000000)
+
+/* Hypervisor ID at physical SPCI instance */
+#define HYP_ID          (0)
+
+/* By convention, SP IDs (as opposed to VM IDs) have bit 15 set */
+#define SP_ID(x)        ((x) | (1 << 15))
+
+typedef unsigned short spci_vm_id_t;
+typedef unsigned short spci_vm_count_t;
+typedef unsigned short spci_vcpu_count_t;
+
+/* Functions */
+
+static inline spci_vcpu_count_t spm_vcpu_get_count(spci_vm_id_t vm_id)
+{
+	hvc_args args = {
+		.fid = SPM_VCPU_GET_COUNT,
+		.arg1 = vm_id
+	};
+
+	hvc_ret_values ret = tftf_hvc(&args);
+
+	return ret.ret0;
+}
+
+static inline spci_vm_count_t spm_vm_get_count(void)
+{
+	hvc_args args = {
+		.fid = SPM_VM_GET_COUNT
+	};
+
+	hvc_ret_values ret = tftf_hvc(&args);
+
+	return ret.ret0;
+}
+
+static inline void spm_debug_log(char c)
+{
+	hvc_args args = {
+		.fid = SPM_DEBUG_LOG,
+		.arg1 = c
+	};
+
+	(void)tftf_hvc(&args);
+}
+
+static inline smc_ret_values spci_id_get(void)
+{
+	smc_args args = {
+		.fid = SPCI_ID_GET
+	};
+
+	return tftf_smc(&args);
+}
+
+static inline smc_ret_values spci_msg_wait(void)
+{
+	smc_args args = {
+		.fid = SPCI_MSG_WAIT
+	};
+
+	return tftf_smc(&args);
+}
+
+/* Send response through registers using direct messaging */
+static inline smc_ret_values spci_msg_send_direct_resp(spci_vm_id_t sender_vm_id,
+						spci_vm_id_t target_vm_id,
+						uint32_t message)
+{
+	smc_args args = {
+		.fid = SPCI_MSG_SEND_DIRECT_RESP_SMC32,
+		.arg1 = ((uint32_t)sender_vm_id << 16) | target_vm_id,
+		.arg3 = message
+	};
+
+	return tftf_smc(&args);
+}
+
+static inline smc_ret_values spci_error(int32_t error_code)
+{
+	smc_args args = {
+		.fid = SPCI_ERROR,
+		.arg1 = 0,
+		.arg2 = error_code
+	};
+
+	return tftf_smc(&args);
+}
+
+#endif /* __SPCI_HELPERS_H__ */