summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>2017-03-15 12:58:14 +0000
committerSandrine Bailleux <sandrine.bailleux@arm.com>2017-05-16 14:03:01 +0100
commit834ea4ab334344d47967c97ee73e16754e3b9de4 (patch)
tree1354ebedc65ae0d8b83ad8155c56fa61381463e3 /tests
parentf1e2be4f913d162d7b72a1abdbdc6145f184ed69 (diff)
Add test cases for state switch ARM SiP service
This test suite validates the execution state switch of a non-secure EL (from AArch32 to AArch64, and vice versa) by issuing ARM SiP service SMC with varying parameters. A cookie is shared between both states. A field in the cooke is updated from the other state to signal that state switch did indeed happen. The suite is not AArch32-ready. All test cases will report as skipped. Change-Id: I269788fb19ed5d366c05fcf2cbd9d0b2cae6e2d0 Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/runtime_services/sip_service/test_exec_state_switch.c337
-rw-r--r--tests/runtime_services/sip_service/test_exec_state_switch_asm.S202
-rw-r--r--tests/tests-common.xml12
-rw-r--r--tests/tests.mk2
4 files changed, 553 insertions, 0 deletions
diff --git a/tests/runtime_services/sip_service/test_exec_state_switch.c b/tests/runtime_services/sip_service/test_exec_state_switch.c
new file mode 100644
index 0000000..ef60bd8
--- /dev/null
+++ b/tests/runtime_services/sip_service/test_exec_state_switch.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This test suite validates the execution state switch of a non-secure EL (from
+ * AArch32 to AArch64, and vice versa) by issuing ARM SiP service SMC with
+ * varying parameters. A cookie is shared between both states. A field in the
+ * cookie is updated from the other state to signal that state switch did indeed
+ * happen.
+ *
+ * Note that the suite is not AArch32-ready. All test cases will report as
+ * skipped.
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <events.h>
+#include <plat_topology.h>
+#include <power_management.h>
+#include <psci.h>
+#include <tftf_lib.h>
+
+/* Definitions from TF arm_sip_svc.h */
+#define ARM_SIP_SVC_VERSION 0x8200ff03
+#define ARM_SIP_SVC_EXE_STATE_SWITCH 0x82000020
+
+/* State switch error codes from SiP service */
+#define STATE_SW_E_PARAM (-2)
+#define STATE_SW_E_DENIED (-3)
+
+#define SIP_VERSION_OK 1
+
+#define HI32(val) (((u_register_t) (val)) >> 32)
+#define LO32(val) ((uint32_t) (u_register_t) (val))
+
+/* A cookie shared between states for information exchange */
+typedef struct {
+ uint32_t pc_hi;
+ uint32_t pc_lo;
+ uint64_t sp;
+ uint32_t success;
+} state_switch_cookie_t;
+
+state_switch_cookie_t state_switch_cookie;
+static event_t secondary_booted __unused;
+
+/*
+ * SiP service version check. Also a signal for test cases to execute or skip
+ * altogether.
+ */
+static int sip_version_check __unused;
+
+/* AArch32 instructions to switch state back to AArch64, stored as data */
+extern void *state_switch_a32_entry;
+
+extern int do_state_switch(void *);
+
+/*
+ * @Test_Aim@ Issue a system reset to initiate state switch SMC call that's part
+ * of ARM SiP service. System reset is required because the state switch SMC
+ * requires that no secondaries have been brought up since booting.
+ */
+test_result_t test_exec_state_switch_reset_before(void)
+{
+#ifdef AARCH64
+ int version;
+ smc_args sip_version_smc = { ARM_SIP_SVC_VERSION };
+ smc_args reset = { SMC_PSCI_SYSTEM_RESET };
+ smc_ret_values smc_ret;
+
+#if NEW_TEST_SESSION
+ /*
+ * This tests suite must start with a system reset. Following a reset,
+ * we expect TFTF to proceed with the rest of test cases. With
+ * NEW_TEST_SESSION set when built, TFTF will run this test case again
+ * after reset. Thus we'll continue resetting forever.
+ *
+ * If NEW_TEST_SESSION is set, skip this test case. sip_version_check
+ * won't be set to SIP_VERSION_OK, thereby skipping rest of test cases
+ * as well.
+ */
+ tftf_testcase_printf("This suite needs TFTF built with NEW_TEST_SESSION=0\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+
+ /*
+ * Query system ARM SiP service version. State switch is available since
+ * version 0.2.
+ */
+ smc_ret = tftf_smc(&sip_version_smc);
+ if (((int) smc_ret.ret0) >= 0) {
+ version = (smc_ret.ret0 << 8) | (smc_ret.ret1 & 0xff);
+ if (version >= 0x02)
+ sip_version_check = SIP_VERSION_OK;
+ } else {
+ tftf_testcase_printf("Test needs SiP service version 0.2 or later\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * This test will be continuously re-entered after reboot, until it
+ * returns success.
+ */
+ if (tftf_is_rebooted())
+ return TEST_RESULT_SUCCESS;
+
+ tftf_testcase_printf("Issuing system reset before state switch\n");
+
+ tftf_notify_reboot();
+ tftf_smc(&reset);
+
+ /* System reset is not expected to return */
+ return TEST_RESULT_FAIL;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
+
+/*
+ * @Test_Aim@ Request execution state switch with invalid entry point. Expect
+ * parameter error when switching from AArch64 to AArch32.
+ */
+test_result_t test_exec_state_switch_invalid_pc(void)
+{
+#ifdef AARCH64
+ int ret;
+
+ smc_args args = {
+ .arg0 = ARM_SIP_SVC_EXE_STATE_SWITCH,
+ .arg1 = (u_register_t) -1,
+ .arg2 = LO32(&state_switch_a32_entry),
+ .arg3 = HI32(&state_switch_cookie),
+ .arg4 = LO32(&state_switch_cookie)
+ };
+
+ if (sip_version_check != SIP_VERSION_OK)
+ return TEST_RESULT_SKIPPED;
+
+ state_switch_cookie.success = 0;
+ ret = do_state_switch(&args);
+ if (state_switch_cookie.success || (ret != STATE_SW_E_PARAM))
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
+
+/*
+ * @Test_Aim@ Request execution state switch with context_hi, and upper part of
+ * context_lo set. Expect failure as they're not supposed to be set when
+ * switching from AArch64 to AArch32.
+ */
+test_result_t test_exec_state_switch_invalid_ctx(void)
+{
+#ifdef AARCH64
+ int ret;
+
+ smc_args args = {
+ .arg0 = ARM_SIP_SVC_EXE_STATE_SWITCH,
+ .arg1 = HI32(&state_switch_a32_entry),
+ .arg2 = LO32(&state_switch_a32_entry),
+ .arg3 = -1,
+ .arg4 = LO32(&state_switch_cookie)
+ };
+
+ if (sip_version_check != SIP_VERSION_OK)
+ return TEST_RESULT_SKIPPED;
+
+ state_switch_cookie.success = 0;
+ ret = do_state_switch(&args);
+ if (state_switch_cookie.success || (ret != STATE_SW_E_PARAM))
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
+
+/*
+ * @Test_Aim@ Perform execution state switch, and back. We don't expect any
+ * failures.
+ */
+test_result_t test_exec_state_switch_valid(void)
+{
+#ifdef AARCH64
+ int ret;
+
+ smc_args args = {
+ .arg0 = ARM_SIP_SVC_EXE_STATE_SWITCH,
+ .arg1 = HI32(&state_switch_a32_entry),
+ .arg2 = LO32(&state_switch_a32_entry),
+ .arg3 = HI32(&state_switch_cookie),
+ .arg4 = LO32(&state_switch_cookie)
+ };
+
+ if (sip_version_check != SIP_VERSION_OK)
+ return TEST_RESULT_SKIPPED;
+
+ /* Make sure that we've a 32-bit PC to enter AArch32 */
+ if (HI32(&state_switch_a32_entry)) {
+ tftf_testcase_printf("AArch32 PC wider than 32 bits. Test skipped; needs re-link\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /*
+ * Perform a state switch to 32 and back. Expect success field in the
+ * cookie to be set and return code zero,
+ */
+ state_switch_cookie.success = 0;
+ ret = do_state_switch(&args);
+ if (!state_switch_cookie.success || (ret != 0))
+ return TEST_RESULT_FAIL;
+
+ return TEST_RESULT_SUCCESS;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
+
+/*
+ * Entry point for the secondary CPU. Send an event to the caller and returns
+ * immediately.
+ */
+static inline test_result_t cpu_ping(void)
+{
+#ifdef AARCH64
+ /* Tell the lead CPU that the calling CPU has entered the test */
+ tftf_send_event(&secondary_booted);
+
+ /*
+ * When returning from the function, the TFTF framework will power CPUs
+ * down, without this test needing to do anything
+ */
+ return TEST_RESULT_SUCCESS;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
+
+/*
+ * @Test_Aim@ Power on any secondary and request a state switch. We expect the
+ * request to be denied because a secondary had been brought up.
+ */
+test_result_t test_exec_state_switch_after_cpu_on(void)
+{
+#ifdef AARCH64
+ u_register_t other_mpidr, my_mpidr;
+ int ret;
+
+ smc_args args = {
+ .arg0 = ARM_SIP_SVC_EXE_STATE_SWITCH,
+ .arg1 = HI32(&state_switch_a32_entry),
+ .arg2 = LO32(&state_switch_a32_entry),
+ .arg3 = HI32(&state_switch_cookie),
+ .arg4 = LO32(&state_switch_cookie)
+ };
+
+ if (sip_version_check != SIP_VERSION_OK)
+ return TEST_RESULT_SKIPPED;
+
+ /* Make sure that we've a 32-bit PC to enter AArch32 */
+ if (HI32(&state_switch_a32_entry)) {
+ tftf_testcase_printf("AArch32 PC wider than 32 bits. Test skipped; needs re-link\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ tftf_init_event(&secondary_booted);
+
+ /* Find a valid CPU to power on */
+ my_mpidr = read_mpidr_el1() & MPID_MASK;
+ other_mpidr = tftf_find_any_cpu_other_than(my_mpidr);
+ if (other_mpidr == INVALID_MPID) {
+ tftf_testcase_printf("Couldn't find a valid other CPU\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Power on the other CPU */
+ ret = tftf_cpu_on(other_mpidr, (uintptr_t) cpu_ping, 0);
+ if (ret != PSCI_E_SUCCESS) {
+ INFO("powering on %llx failed", (unsigned long long)
+ other_mpidr);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Wait for flag to proceed */
+ tftf_wait_for_event(&secondary_booted);
+
+ /*
+ * Request a state switch to 32 and back. Expect failure since we've
+ * powerd a secondary on.
+ */
+ state_switch_cookie.success = 0;
+ ret = do_state_switch(&args);
+ if ((state_switch_cookie.success != 0) || (ret != STATE_SW_E_DENIED))
+ return TEST_RESULT_FAIL;
+ else
+ return TEST_RESULT_SUCCESS;
+#else
+ tftf_testcase_printf("Test not ported to AArch32\n");
+ return TEST_RESULT_SKIPPED;
+#endif
+}
diff --git a/tests/runtime_services/sip_service/test_exec_state_switch_asm.S b/tests/runtime_services/sip_service/test_exec_state_switch_asm.S
new file mode 100644
index 0000000..d010231
--- /dev/null
+++ b/tests/runtime_services/sip_service/test_exec_state_switch_asm.S
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm_macros_common.S>
+
+#define COOKIE_SIZE 20
+
+#ifdef AARCH64
+/* int do_state_switch(void *) */
+ .globl do_state_switch
+func do_state_switch
+ /* Temporarily save beginning of stack */
+ mov x7, sp
+
+ /*
+ * When asking to switch execution state, we can't expect general
+ * purpose registers hold their values. EL3 might clear them all; even
+ * if EL3 were to preserve them, the register width shrinks and then
+ * expands, leaving the upper part unknown. So save them before and
+ * restore after call to switch.
+ */
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x19, [sp, #-16]!
+ stp x20, x21, [sp, #-16]!
+ stp x22, x23, [sp, #-16]!
+ stp x24, x25, [sp, #-16]!
+ stp x26, x27, [sp, #-16]!
+ stp x28, x29, [sp, #-16]!
+
+ /*
+ * State switch effectively means a soft reset; so SCTLR will lose its
+ * value too.
+ */
+ mrs x1, CurrentEL
+ cmp x1, #(2 << 2)
+ b.ne 1f
+ mrs x1, sctlr_el2
+ b 2f
+1:
+ mrs x1, sctlr_el1
+2:
+ stp x30, x1, [sp, #-16]!
+
+ /* Store the PC in the cookie when switching back to AArch64 */
+ ldr x4, =state_switch_cookie
+ adr x2, do_switch_back
+ mov w1, w2
+ lsr x1, x1, #32
+ str w1, [x4, #0] /* PC hi */
+ str w2, [x4, #4] /* PC lo */
+
+ /* Store valid stack pointer in cookie */
+ mov x8, sp
+ str x8, [x4, #8]
+
+ /* Stash stack and LR before calling functions */
+ mov x28, x7
+ mov x29, x30
+
+ mov x10, x0
+
+ /*
+ * Clean and invalidate cookie memory as it's going to be accessed with
+ * MMU off in the new state.
+ */
+ mov x0, x4
+ ldr x1, =COOKIE_SIZE
+ bl flush_dcache_range
+
+ /*
+ * Flush stack context saved on stack as it'll be accessed immediately
+ * after switching back, with MMU off.
+ */
+ mov x0, x8
+ sub x1, x28, x8
+ bl flush_dcache_range
+
+ /* Prepare arguments for state switch SMC */
+ ldr x0, [x10], #8
+ ldr x1, [x10], #8
+ ldr x2, [x10], #8
+ ldr x3, [x10], #8
+ ldr x4, [x10], #8
+
+ /* Switch state */
+ smc #0
+
+ /*
+ * We reach here only if the SMC failed. If so, restore previously
+ * modified callee-saved registers, rewind stack, and return to caller
+ * with the error code from SMC.
+ */
+ mov x1, x28
+ mov x2, x29
+ ldp x28, x29, [sp, #16]
+ mov sp, x1
+ ret x2
+
+restore_context:
+ /* Restore context */
+ ldp x30, x1, [sp], #16
+ ldp x28, x29, [sp], #16
+ ldp x26, x27, [sp], #16
+ ldp x24, x25, [sp], #16
+ ldp x22, x23, [sp], #16
+ ldp x20, x21, [sp], #16
+ ldp x18, x19, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+
+ dsb sy
+ mrs x0, CurrentEL
+ cmp x0, #(2 << 2)
+ b.ne 1f
+ msr sctlr_el2, x1
+ b 2f
+1:
+ msr sctlr_el1, x1
+2:
+ isb
+
+ mov x0, #0
+ ret
+endfunc do_state_switch
+
+/* AArch64 entry point when switching back from AArch32 */
+do_switch_back:
+ /* w0 and w1 have the cookie */
+ lsl x0, x0, #32
+ orr x0, x1, x0
+
+ ldr x1, [x0, #8]
+ mov sp, x1
+
+ b restore_context
+
+ .section .data, "aw"
+
+/* AArch32 instructions to switch state back to AArch64, stored as data */
+ .align 2
+ .globl state_switch_a32_entry
+state_switch_a32_entry:
+ /* Use the same context when switching back */
+ .word 0xe1a03000 /* mov r3, r0 */
+ .word 0xe1a04001 /* mov r4, r1 */
+
+ /* Set success flag in cookie */
+ .word 0xe3a00001 /* mov r0, #1 */
+ .word 0xe5810010 /* str r0, [r1, #16] */
+
+ /* Setup arguments for SMC */
+ .word 0xe3a00020 /* mov r0, #0x0020 */
+ .word 0xe3480200 /* movt r0, #0x8200 */
+
+ .word 0xe5912004 /* ldr r2, [r1, #4] */
+ .word 0xe5911000 /* ldr r1, [r1, #0] */
+ .word 0xe1600070 /* smc #0x0 */
+ .word 0xeafffffe /* b . */
+
+#else /* !AARCH64 */
+
+/* Not supported on AArch32 yet */
+func do_state_switch
+ mov r0, #-1
+ bx lr
+endfunc do_state_switch
+
+#endif /* AARCH64 */
diff --git a/tests/tests-common.xml b/tests/tests-common.xml
index fc793f9..feea931 100644
--- a/tests/tests-common.xml
+++ b/tests/tests-common.xml
@@ -147,6 +147,18 @@
<testcase name="Test Secure FIQ while TSP is preempted" function="tsp_fiq_while_int" />
</testsuite>
+ <!-- Test suite exercising execution state switch SiP service.
+ 'test_exec_state_switch_reset_before' must execute first in the suite,
+ and 'test_exec_state_switch_after_cpu_on' the last. See comments in
+ test_exec_state_switch.c for details -->
+ <testsuite name="State switch" description="Test ARM SiP State Switch service">
+ <testcase name="System reset before state switch" function="test_exec_state_switch_reset_before" />
+ <testcase name="Request state switch with invalid PC" function="test_exec_state_switch_invalid_pc" />
+ <testcase name="Request state switch with invalid context" function="test_exec_state_switch_invalid_ctx" />
+ <testcase name="Request a valid state switch" function="test_exec_state_switch_valid" />
+ <testcase name="Request a valid state switch after CPU_ON" function="test_exec_state_switch_after_cpu_on" />
+ </testsuite>
+
</testsuites>
<!-- This testsuite crashes the firmware.
diff --git a/tests/tests.mk b/tests/tests.mk
index e2360f1..58fdea4 100644
--- a/tests/tests.mk
+++ b/tests/tests.mk
@@ -34,6 +34,8 @@ TESTS_SOURCES := tests/framework_validation_tests/test_timer_framework.c \
tests/framework_validation_tests/test_validation_nvm.c \
tests/framework_validation_tests/test_validation_sgi.c \
tests/performance_tests/smc_latencies.c \
+ tests/runtime_services/sip_service/test_exec_state_switch.c \
+ tests/runtime_services/sip_service/test_exec_state_switch_asm.S \
tests/runtime_services/standard_service/pmf/api_tests/runtime_instr/test_pmf_rt_instr.c \
tests/runtime_services/standard_service/psci/api_tests/affinity_info/test_psci_affinity_info.c \
tests/runtime_services/standard_service/psci/api_tests/cpu_hotplug/test_psci_hotplug.c \