From a5b9fa30cebd91082f9fea93d7ef33812910da6a Mon Sep 17 00:00:00 2001
From: Sergey Temerkhanov <s.temerkhanov@gmail.com>
Date: Wed, 14 Oct 2015 09:55:46 -0700
Subject: [PATCH] armv8: Add Secure Monitor/Hypervisor Call (SMC/HVC)
 infrastructure

This commit adds functions issuing calls to secure monitor or
hypervisore. This allows using services such as Power State
Coordination Interface (PSCI) provided by firmware, e.g. ARM
Trusted Firmware (ATF)

The SMC call can destroy all registers declared temporary by the
calling conventions. The clobber list is "x0..x17" because of
this

Signed-off-by: Sergey Temerkhanov <s.temerkhanov@gmail.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Radha Mohan Chintakuntla <rchintakuntla@cavium.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
---
 arch/arm/cpu/armv8/Makefile   |  1 +
 arch/arm/cpu/armv8/fwcall.c   | 75 +++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/system.h | 21 ++++++++++
 3 files changed, 97 insertions(+)
 create mode 100644 arch/arm/cpu/armv8/fwcall.c

diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile
index 48c041bb9b..1c85aa924d 100644
--- a/arch/arm/cpu/armv8/Makefile
+++ b/arch/arm/cpu/armv8/Makefile
@@ -14,6 +14,7 @@ obj-y	+= exceptions.o
 obj-y	+= cache.o
 obj-y	+= tlb.o
 obj-y	+= transition.o
+obj-y	+= fwcall.o
 
 obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
 obj-$(CONFIG_ARCH_ZYNQMP) += zynqmp/
diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c
new file mode 100644
index 0000000000..9efcc5ada9
--- /dev/null
+++ b/arch/arm/cpu/armv8/fwcall.c
@@ -0,0 +1,75 @@
+/**
+ * (C) Copyright 2014, Cavium Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+**/
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <version.h>
+#include <asm/macro.h>
+#include <asm/system.h>
+
+/*
+ * Issue the hypervisor call
+ *
+ * x0~x7: input arguments
+ * x0~x3: output arguments
+ */
+void hvc_call(struct pt_regs *args)
+{
+	asm volatile(
+		"ldr x0, %0\n"
+		"ldr x1, %1\n"
+		"ldr x2, %2\n"
+		"ldr x3, %3\n"
+		"ldr x4, %4\n"
+		"ldr x5, %5\n"
+		"ldr x6, %6\n"
+		"ldr x7, %7\n"
+		"hvc	#0\n"
+		"str x0, %0\n"
+		"str x1, %1\n"
+		"str x2, %2\n"
+		"str x3, %3\n"
+		: "+m" (args->regs[0]), "+m" (args->regs[1]),
+		  "+m" (args->regs[2]), "+m" (args->regs[3])
+		: "m" (args->regs[4]), "m" (args->regs[5]),
+		  "m" (args->regs[6]), "m" (args->regs[7])
+		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+		  "x16", "x17");
+}
+
+/*
+ * void smc_call(arg0, arg1...arg7)
+ *
+ * issue the secure monitor call
+ *
+ * x0~x7: input arguments
+ * x0~x3: output arguments
+ */
+
+void smc_call(struct pt_regs *args)
+{
+	asm volatile(
+		"ldr x0, %0\n"
+		"ldr x1, %1\n"
+		"ldr x2, %2\n"
+		"ldr x3, %3\n"
+		"ldr x4, %4\n"
+		"ldr x5, %5\n"
+		"ldr x6, %6\n"
+		"smc	#0\n"
+		"str x0, %0\n"
+		"str x1, %1\n"
+		"str x2, %2\n"
+		"str x3, %3\n"
+		: "+m" (args->regs[0]), "+m" (args->regs[1]),
+		  "+m" (args->regs[2]), "+m" (args->regs[3])
+		: "m" (args->regs[4]), "m" (args->regs[5]),
+		  "m" (args->regs[6])
+		: "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+		  "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+		  "x16", "x17");
+}
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 393e7afcdd..67cbbc2610 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -1,6 +1,9 @@
 #ifndef __ASM_ARM_SYSTEM_H
 #define __ASM_ARM_SYSTEM_H
 
+#include <common.h>
+#include <linux/compiler.h>
+
 #ifdef CONFIG_ARM64
 
 /*
@@ -105,6 +108,24 @@ void smp_kick_all_cpus(void);
 
 void flush_l3_cache(void);
 
+/*
+ *Issue a hypervisor call in accordance with ARM "SMC Calling convention",
+ * DEN0028A
+ *
+ * @args: input and output arguments
+ *
+ */
+void hvc_call(struct pt_regs *args);
+
+/*
+ *Issue a secure monitor call in accordance with ARM "SMC Calling convention",
+ * DEN0028A
+ *
+ * @args: input and output arguments
+ *
+ */
+void smc_call(struct pt_regs *args);
+
 #endif	/* __ASSEMBLY__ */
 
 #else /* CONFIG_ARM64 */
-- 
2.39.5