trusty: Extend smc function and move to arch specific asm file

Extend trusty smc function to pass 8 registers in both directions. Move
to separate assembly files so r7 can be used (in thumb mode r7 got
corrupted by the inline assembly even though it was specified as an
output).

Signed-off-by: Arve Hjønnevåg <arve@android.com>
Bug: 128698138
Change-Id: I76fc5169182d687981fc6ce854f6489e055cfd01
diff --git a/drivers/trusty/Kconfig b/drivers/trusty/Kconfig
index 6fc3398..32a8ab0 100644
--- a/drivers/trusty/Kconfig
+++ b/drivers/trusty/Kconfig
@@ -8,6 +8,18 @@
 	tristate "Trusty"
 	default n
 
+config TRUSTY_SMC_ARM
+	tristate
+	depends on TRUSTY
+	depends on ARM
+	default y
+
+config TRUSTY_SMC_ARM64
+	tristate
+	depends on TRUSTY
+	depends on ARM64
+	default y
+
 config TRUSTY_FIQ
 	tristate
 	depends on TRUSTY
diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile
index e83e1dd..e7174ff 100644
--- a/drivers/trusty/Makefile
+++ b/drivers/trusty/Makefile
@@ -3,6 +3,8 @@
 #
 
 obj-$(CONFIG_TRUSTY)		+= trusty.o
+obj-$(CONFIG_TRUSTY_SMC_ARM)	+= trusty-smc-arm.o
+obj-$(CONFIG_TRUSTY_SMC_ARM64)	+= trusty-smc-arm64.o
 obj-$(CONFIG_TRUSTY)		+= trusty-irq.o
 obj-$(CONFIG_TRUSTY_FIQ)	+= trusty-fiq.o
 obj-$(CONFIG_TRUSTY_FIQ_ARM)	+= trusty-fiq-arm.o
diff --git a/drivers/trusty/trusty-smc-arm.S b/drivers/trusty/trusty-smc-arm.S
new file mode 100644
index 0000000..0145a36
--- /dev/null
+++ b/drivers/trusty/trusty-smc-arm.S
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 Google, Inc.
+ */
+
+#include <linux/linkage.h>
+
+.arch_extension sec
+
+ENTRY(trusty_smc8)
+    /* Save stack location where r3-r7 smc arguments are stored */
+    mov     r12, sp
+
+    /* Save original r4-r7 values as caller expects these to be preserved */
+    push    {r4-r7}
+
+    /* Save return value pointer and return address */
+    push    {r0, lr}
+
+    /* arm abi shifts arguments when returning a struct, shift them back */
+    mov     r0, r1
+    mov     r1, r2
+    mov     r2, r3
+
+    /* Load stack based arguments */
+    ldmia   r12, {r3-r7}
+
+    smc     #0
+
+    /* Restore return address and get return value pointer */
+    pop     {r12, lr}
+
+    /* Copy 8-register smc return value to struct smc_ret8 return value */
+    stmia   r12, {r0-r7}
+
+    /* Restore original r4-r7 values */
+    pop     {r4-r7}
+
+    /* Return */
+    bx      lr
diff --git a/drivers/trusty/trusty-smc-arm64.S b/drivers/trusty/trusty-smc-arm64.S
new file mode 100644
index 0000000..90a60dd
--- /dev/null
+++ b/drivers/trusty/trusty-smc-arm64.S
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 Google, Inc.
+ */
+
+#include <linux/linkage.h>
+
+.macro push ra, rb
+stp \ra, \rb, [sp,#-16]!
+.endm
+
+.macro pop ra, rb
+ldp \ra, \rb, [sp], #16
+.endm
+
+lr .req x30
+
+ENTRY(trusty_smc8)
+    /*
+     * Save x8 (return value ptr) and lr. The SMC calling convention says el3
+     * does not need to preserve x8. The normal ABI does not require either x8
+     * or lr to be preserved.
+     */
+    push    x8, lr
+    smc     #0
+    pop     x8, lr
+
+    /* Copy 8-register smc return value to struct smc_ret8 return value */
+    stp     x0, x1, [x8], #16
+    stp     x2, x3, [x8], #16
+    stp     x4, x5, [x8], #16
+    stp     x6, x7, [x8], #16
+
+    ret
diff --git a/drivers/trusty/trusty-smc.h b/drivers/trusty/trusty-smc.h
new file mode 100644
index 0000000..7882663
--- /dev/null
+++ b/drivers/trusty/trusty-smc.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 Google, Inc.
+ */
+
+#pragma once
+
+#include <linux/types.h>
+
+struct smc_ret8 {
+	ulong r0;
+	ulong r1;
+	ulong r2;
+	ulong r3;
+	ulong r4;
+	ulong r5;
+	ulong r6;
+	ulong r7;
+};
+
+struct smc_ret8 trusty_smc8(ulong r0, ulong r1, ulong r2, ulong r3,
+			    ulong r4, ulong r5, ulong r6, ulong r7);
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index 789c48a..285fab9 100644
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -12,7 +12,6 @@
  *
  */
 
-#include <asm/compiler.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -28,6 +27,8 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
 
+#include "trusty-smc.h"
+
 struct trusty_state;
 static struct platform_driver trusty_driver;
 
@@ -51,45 +52,9 @@ struct trusty_state {
 	struct device_dma_parameters dma_parms;
 };
 
-#ifdef CONFIG_ARM64
-#define SMC_ARG0		"x0"
-#define SMC_ARG1		"x1"
-#define SMC_ARG2		"x2"
-#define SMC_ARG3		"x3"
-#define SMC_ARCH_EXTENSION	""
-#define SMC_REGISTERS_TRASHED	"x4","x5","x6","x7","x8","x9","x10","x11", \
-				"x12","x13","x14","x15","x16","x17"
-#else
-#define SMC_ARG0		"r0"
-#define SMC_ARG1		"r1"
-#define SMC_ARG2		"r2"
-#define SMC_ARG3		"r3"
-#define SMC_ARCH_EXTENSION	".arch_extension sec\n"
-#define SMC_REGISTERS_TRASHED	"ip"
-#endif
-
 static inline ulong smc(ulong r0, ulong r1, ulong r2, ulong r3)
 {
-	register ulong _r0 asm(SMC_ARG0) = r0;
-	register ulong _r1 asm(SMC_ARG1) = r1;
-	register ulong _r2 asm(SMC_ARG2) = r2;
-	register ulong _r3 asm(SMC_ARG3) = r3;
-
-	asm volatile(
-		__asmeq("%0", SMC_ARG0)
-		__asmeq("%1", SMC_ARG1)
-		__asmeq("%2", SMC_ARG2)
-		__asmeq("%3", SMC_ARG3)
-		__asmeq("%4", SMC_ARG0)
-		__asmeq("%5", SMC_ARG1)
-		__asmeq("%6", SMC_ARG2)
-		__asmeq("%7", SMC_ARG3)
-		SMC_ARCH_EXTENSION
-		"smc	#0"	/* switch to secure world */
-		: "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3)
-		: "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3)
-		: SMC_REGISTERS_TRASHED);
-	return _r0;
+	return trusty_smc8(r0, r1, r2, r3, 0, 0, 0, 0).r0;
 }
 
 s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)