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));
}