Support for extended register usage in SMCCC v1.2 spec

The new version of SMC Calling Convention spec makes X0-X7/W0-W7/R0-R7
registers available for returning results and X1-X7/W1-W7/R1-R7 for
passing arguments during SMC calls.

This patch makes necessary changes to support the update in register
usage and also enhances existing test case to check for expected
behavior across SMC call.

Link to the SMCCC spec:
https://developer.arm.com/docs/den0028/c

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I9e5a3e4f9de388cb9a7426b0eae1c0fa1229292a
diff --git a/include/lib/tftf_lib.h b/include/lib/tftf_lib.h
index 3f60fec..9812252 100644
--- a/include/lib/tftf_lib.h
+++ b/include/lib/tftf_lib.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -123,9 +123,9 @@
 void waitus(uint64_t us);
 
 /*
- * SMC calls take a function identifier and up to 6 arguments.
- * Additionally, for SMC calls that originate from EL2, an optional seventh
- * argument can be added. Given that TFTF runs in EL2, we need to be able to
+ * SMC calls take a function identifier and up to 7 arguments.
+ * Additionally, few SMC calls that originate from EL2 leverage the seventh
+ * argument explicitly. Given that TFTF runs in EL2, we need to be able to
  * specify it.
  */
 typedef struct {
@@ -141,12 +141,16 @@
 	u_register_t	arg7;
 } smc_args;
 
-/* SMC calls can return up to 4 register values */
+/* SMC calls can return up to 8 register values */
 typedef struct {
 	u_register_t	ret0;
 	u_register_t	ret1;
 	u_register_t	ret2;
 	u_register_t	ret3;
+	u_register_t	ret4;
+	u_register_t	ret5;
+	u_register_t	ret6;
+	u_register_t	ret7;
 } smc_ret_values;
 
 /*
diff --git a/lib/smc/aarch32/asm_smc.S b/lib/smc/aarch32/asm_smc.S
index 908b8d0..1070864 100644
--- a/lib/smc/aarch32/asm_smc.S
+++ b/lib/smc/aarch32/asm_smc.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2016-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,10 +26,10 @@
 	smc	#0
 
 	/*
-	 * The returned values from the SMC are in r0-r3, put them in the
+	 * The returned values from the SMC are in r0-r7, put them in the
 	 * 'smc_ret_values' return structure.
 	 */
-	stm	r8, {r0 - r3}
+	stm	r8, {r0 - r7}
 
 	pop	{r4 - r9}
 	bx	lr
diff --git a/lib/smc/aarch64/asm_smc.S b/lib/smc/aarch64/asm_smc.S
index 1180f51..c3044a4 100644
--- a/lib/smc/aarch64/asm_smc.S
+++ b/lib/smc/aarch64/asm_smc.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,17 +34,19 @@
 	 */
 	str	x8, [sp, #-16]!
 
-	/* SMC arguments are already stored in x0-x6 */
+	/* SMC arguments are already stored in x0-x7 */
 	smc	#0
 
 	/* Pop x8 into a caller-saved register */
 	ldr	x9, [sp], #16
 
 	/*
-	 * Return values are stored in x0-x3, put them in the 'smc_ret_values'
+	 * Return values are stored in x0-x7, put them in the 'smc_ret_values'
 	 * return structure
 	 */
 	stp	x0, x1, [x9, #0]
 	stp	x2, x3, [x9, #16]
+	stp	x4, x5, [x9, #32]
+	stp	x6, x7, [x9, #48]
 	ret
 endfunc asm_tftf_smc64
diff --git a/tftf/tests/runtime_services/generic/generic_smc.c b/tftf/tests/runtime_services/generic/generic_smc.c
index defb843..dc0b102 100644
--- a/tftf/tests/runtime_services/generic/generic_smc.c
+++ b/tftf/tests/runtime_services/generic/generic_smc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -58,9 +58,12 @@
 		return true;
 	} else {
 		tftf_testcase_printf(
-			"Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {0x%lx,0x%lx,0x%lx,0x%lx}.\n",
+			"Got {0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx}, \
+			expected {0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx}.\n",
 			ret.ret0, ret.ret1, ret.ret2, ret.ret3,
-			expect->ret0, expect->ret1, expect->ret2, expect->ret3);
+			ret.ret4, ret.ret5, ret.ret6, ret.ret7,
+			expect->ret0, expect->ret1, expect->ret2, expect->ret3,
+			expect->ret4, expect->ret5, expect->ret6, expect->ret7);
 		return false;
 	}
 }
@@ -78,7 +81,7 @@
  * If the values do not match, write an error message in the test report.
  */
 static bool smc_check_match(const smc_args *args, const smc_ret_values *expect,
-			    const bool do_check[4], const bool allow_zeros[4])
+			    const bool do_check[8], const bool allow_zeros[8])
 {
 	smc_ret_values ret = tftf_smc(args);
 
@@ -88,14 +91,18 @@
 	if ((do_check[0] && CHK_RET(ret.ret0, expect->ret0, allow_zeros[0])) ||
 	    (do_check[1] && CHK_RET(ret.ret1, expect->ret1, allow_zeros[1])) ||
 	    (do_check[2] && CHK_RET(ret.ret2, expect->ret2, allow_zeros[2])) ||
-	    (do_check[3] && CHK_RET(ret.ret3, expect->ret3, allow_zeros[3]))) {
+	    (do_check[3] && CHK_RET(ret.ret3, expect->ret3, allow_zeros[3])) ||
+	    (do_check[4] && CHK_RET(ret.ret4, expect->ret4, allow_zeros[4])) ||
+	    (do_check[5] && CHK_RET(ret.ret5, expect->ret5, allow_zeros[5])) ||
+	    (do_check[6] && CHK_RET(ret.ret6, expect->ret6, allow_zeros[6])) ||
+	    (do_check[7] && CHK_RET(ret.ret7, expect->ret7, allow_zeros[7]))) {
 
 #undef CHK_RET
 		/*
 		 * Build an error message where unchecked SMC return values are
 		 * displayed as '*'.
 		 */
-		char expect_str[4][28];
+		char expect_str[8][28];
 #define BUILD_STR(_buf, _buf_size, _do_check, _allow_zero, _expect)	\
 		do {							\
 			if (_do_check) {				\
@@ -120,11 +127,22 @@
 			do_check[2], allow_zeros[2], expect->ret2);
 		BUILD_STR(expect_str[3], sizeof(expect_str[3]),
 			do_check[3], allow_zeros[3], expect->ret3);
+		BUILD_STR(expect_str[4], sizeof(expect_str[4]),
+			do_check[4], allow_zeros[4], expect->ret4);
+		BUILD_STR(expect_str[5], sizeof(expect_str[5]),
+			do_check[5], allow_zeros[5], expect->ret5);
+		BUILD_STR(expect_str[6], sizeof(expect_str[6]),
+			do_check[6], allow_zeros[6], expect->ret6);
+		BUILD_STR(expect_str[7], sizeof(expect_str[7]),
+			do_check[7], allow_zeros[7], expect->ret7);
 #undef BUILD_STR
 		tftf_testcase_printf(
-			"Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {%s,%s,%s,%s}.\n",
+		"Got {0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx}, \
+			expected {%s,%s,%s,%s,%s,%s,%s,%s}.\n",
 			ret.ret0, ret.ret1, ret.ret2, ret.ret3,
-			expect_str[0], expect_str[1], expect_str[2], expect_str[3]);
+			ret.ret4, ret.ret5, ret.ret6, ret.ret7,
+			expect_str[0], expect_str[1], expect_str[2], expect_str[3],
+			expect_str[4], expect_str[5], expect_str[6], expect_str[7]);
 
 		return false;
 	} else {
@@ -142,16 +160,20 @@
 	/* Invalid Fast SMC32. */
 	const smc_args args2 = {
 		make_smc_fid(SMC_TYPE_FAST, SMC_32, OEN_ARM_START, INVALID_FN),
-		0x11111111, 0x22222222, 0x33333333 };
+		0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	const smc_ret_values ret2
-		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
+		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	FAIL_IF(!smc_check_eq(&args2, &ret2));
 
 	/* Valid Fast SMC32 using 1 return value. */
 	const smc_args args3
-		= { SMC_PSCI_VERSION, 0x44444444, 0x55555555, 0x66666666 };
+		= { SMC_PSCI_VERSION, 0x44444444, 0x55555555, 0x66666666,
+		0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 	const smc_ret_values ret3
-		= { psci_version, 0x44444444, 0x55555555, 0x66666666 };
+		= { psci_version, 0x44444444, 0x55555555, 0x66666666,
+		0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 	FAIL_IF(!smc_check_eq(&args3, &ret3));
 
 	return TEST_RESULT_SUCCESS;
@@ -167,9 +189,11 @@
 	/* Invalid function number, SMC64 Yielding. */
 	const smc_args args2 = {
 		make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_ARM_START, INVALID_FN),
-		0x11111111, 0x22222222, 0x33333333 };
+		0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	const smc_ret_values ret2
-		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
+		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	FAIL_IF(!smc_check_eq(&args2, &ret2));
 
 	/*
@@ -186,7 +210,8 @@
 	 */
 	const smc_args args3 = {
 		make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_TOS_START, INVALID_FN),
-		0x44444444, 0x55555555, 0x66666666 };
+		0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888,
+		0x99999999, 0xaaaaaaaa };
 
 	if (is_trusted_os_present(NULL)) {
 		/*
@@ -194,14 +219,17 @@
 		 * should at least preserve or fill by zeroes the values of
 		 * x1-x3.
 		 */
-		const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666 };
-		const bool check[4] = { false, true, true, true };
-		const bool allow_zeros[4] = { false, true, true, true };
+		const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666,
+			0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
+		const bool check[8] = { false, true, true, true, true, true, true, true };
+		const bool allow_zeros[8] = { false, true, true, true,
+						true, true, true, true };
 
 		FAIL_IF(!smc_check_match(&args3, &ret3, check, allow_zeros));
 	} else {
 		const smc_ret_values ret3
-			= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
+			= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666,
+			0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 		FAIL_IF(!smc_check_eq(&args3, &ret3));
 	}
 
@@ -218,9 +246,11 @@
 	/* Invalid SMC function number, Fast SMC64. */
 	const smc_args args2 = {
 		make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
-		0x11111111, 0x22222222, 0x33333333 };
+		0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	const smc_ret_values ret2
-		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
+		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333,
+		0x44444444, 0x55555555, 0x66666666, 0x77777777 };
 	FAIL_IF(!smc_check_eq(&args2, &ret2));
 
 	/*
@@ -228,9 +258,11 @@
 	 * forbidden to use the SMC64 calling convention.
 	 */
 	const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
-		0x44444444, 0x55555555, 0x66666666 };
+		0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888,
+		0x99999999, 0xaaaaaaaa };
 	const smc_ret_values ret3
-		= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
+		= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666,
+		0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 	FAIL_IF(!smc_check_eq(&args3, &ret3));
 
 	return TEST_RESULT_SUCCESS;
@@ -245,16 +277,20 @@
 	/* Invalid function number, Fast SMC64. */
 	const smc_args args2 = {
 		make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
-		0x11111111, 0x22222222, 0x33333333 };
+		0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555,
+		0x66666666, 0x77777777 };
 	const smc_ret_values ret2
-		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
+		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	FAIL_IF(!smc_check_eq(&args2, &ret2));
 
 	/* Valid Fast SMC64 using 1 return value. */
 	const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
-				 0x44444444, 0x55555555, 0x66666666 };
+			0x44444444, 0x55555555, 0x66666666, 0x77777777,
+			0x88888888, 0x99999999, 0xaaaaaaaa };
 	const smc_ret_values ret3
-		= { PSCI_E_INVALID_PARAMS, 0x44444444, 0x55555555, 0x66666666 };
+		= { PSCI_E_INVALID_PARAMS, 0x44444444, 0x55555555, 0x66666666,
+		0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 	FAIL_IF(!smc_check_eq(&args3, &ret3));
 
 	return TEST_RESULT_SUCCESS;
@@ -281,9 +317,11 @@
 	/* Invalid function number, SMC32 Yielding. */
 	const smc_args args2 = {
 		make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_ARM_START, INVALID_FN),
-		0x11111111, 0x22222222, 0x33333333 };
+		0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	const smc_ret_values ret2
-		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
+		= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333, 0x44444444,
+		0x55555555, 0x66666666, 0x77777777 };
 	FAIL_IF(!smc_check_eq(&args2, &ret2));
 
 	/*
@@ -300,7 +338,8 @@
 	 */
 	const smc_args args3 = {
 		make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_TOS_START, INVALID_FN),
-		0x44444444, 0x55555555, 0x66666666 };
+		0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888,
+		0x99999999, 0xaaaaaaaa };
 
 	if (is_trusted_os_present(NULL)) {
 		/*
@@ -308,14 +347,17 @@
 		 * should at least preserve or fill by zeroes the values of
 		 * x1-x3.
 		 */
-		const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666 };
-		const bool check[4] = { false, true, true, true };
-		const bool allow_zeros[4] = { false, true, true, true };
+		const smc_ret_values ret3 = { 0, 0x44444444, 0x55555555, 0x66666666,
+			0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
+		const bool check[8] = { false, true, true, true, true, true, true, true };
+		const bool allow_zeros[8] = { false, true, true, true,
+						true, true, true, true };
 
 		FAIL_IF(!smc_check_match(&args3, &ret3, check, allow_zeros));
 	} else {
 		const smc_ret_values ret3
-			= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
+			= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666,
+			0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa };
 		FAIL_IF(!smc_check_eq(&args3, &ret3));
 	}