tests: arm: Add arm_thread_swap_tz test
For testing secure->non-secure thread swapping. This also tests that the FP context is correctly preserved when calling a secure function. Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
This commit is contained in:
parent
aed0643705
commit
17442cece9
7 changed files with 306 additions and 0 deletions
13
tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt
Normal file
13
tests/arch/arm/arm_thread_swap_tz/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(NONE)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
12
tests/arch/arm/arm_thread_swap_tz/Kconfig
Normal file
12
tests/arch/arm/arm_thread_swap_tz/Kconfig
Normal file
|
@ -0,0 +1,12 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2021 Nordic Semicondutor ASA
|
||||
|
||||
config ARM_STORE_EXC_RETURN
|
||||
bool
|
||||
default y if ARM_NONSECURE_FIRMWARE
|
||||
help
|
||||
Redefine this with looser requirements, so the EXC_RETURN value can
|
||||
be checked in the test. This essentially tests that the official
|
||||
requirements are sane.
|
||||
|
||||
source "Kconfig.zephyr"
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Linaro Limited.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
/* This partition table should be used along with TFM configuration:
|
||||
* - TFM_PSA_API=ON (IPC)
|
||||
* - ISOLATION_LEVEL 2
|
||||
* - TEST_S=ON (REGRESSION)
|
||||
* - TEST_NS=ON (REGRESSION)
|
||||
*
|
||||
* In this configuration, TFM binary includes tests. As a consequence,
|
||||
* its size is bloated and it is not possible to set secondary partitions
|
||||
* for secured or non secured images.
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,code-partition = &slot1_partition;
|
||||
};
|
||||
};
|
||||
|
||||
&flash0 {
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
boot_partition: partition@0 {
|
||||
label = "mcuboot";
|
||||
reg = <0x00000000 0x00013000>;
|
||||
read-only;
|
||||
};
|
||||
/* Secure image primary slot */
|
||||
slot0_partition: partition@00013000 {
|
||||
label = "image-0";
|
||||
reg = <0x00013000 0x00038000>;
|
||||
};
|
||||
/* Non-secure image primary slot */
|
||||
slot1_partition: partition@0004B000 {
|
||||
label = "image-1";
|
||||
reg = <0x0004B000 0x0002A000>;
|
||||
};
|
||||
/*
|
||||
* The flash starting at 0x7F000 and ending at
|
||||
* 0x80000 is reserved for the application.
|
||||
*/
|
||||
storage_partition: partition@7F000 {
|
||||
label = "storage";
|
||||
reg = <0x0007F000 0x00001000>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Yestin Sun
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* This partition table should be used along with TFM configuration:
|
||||
* - TFM_PSA_API=ON (IPC)
|
||||
* - ISOLATION_LEVEL 2
|
||||
* - TEST_S=ON (REGRESSION)
|
||||
* - TEST_NS=OFF (By default)
|
||||
*
|
||||
* In this configuration, TFM binary includes tests. As a consequence,
|
||||
* its size is bloated and it is not possible to set secondary partitions
|
||||
* for secured or non secured images.
|
||||
*/
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,code-partition = &slot1_partition;
|
||||
};
|
||||
};
|
||||
|
||||
&flash0 {
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
boot_partition: partition@0 {
|
||||
label = "mcuboot";
|
||||
reg = <0x00000000 0x00019000>;
|
||||
read-only;
|
||||
};
|
||||
/* Secure image primary slot */
|
||||
slot0_partition: partition@00019000 {
|
||||
label = "image-0";
|
||||
reg = <0x00019000 0x00038000>;
|
||||
};
|
||||
/* Non-secure image primary slot */
|
||||
slot1_partition: partition@00051000 {
|
||||
label = "image-1";
|
||||
reg = <0x00051000 0x0002A000>;
|
||||
};
|
||||
/*
|
||||
* The flash starting at 0x7F000 and ending at
|
||||
* 0x80000 is reserved for the application.
|
||||
*/
|
||||
storage_partition: partition@7F000 {
|
||||
label = "storage";
|
||||
reg = <0x0007F000 0x00001000>;
|
||||
};
|
||||
};
|
||||
};
|
13
tests/arch/arm/arm_thread_swap_tz/prj.conf
Normal file
13
tests/arch/arm/arm_thread_swap_tz/prj.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
CONFIG_ZTEST=y
|
||||
CONFIG_ZTEST_THREAD_PRIORITY=0
|
||||
CONFIG_BUILD_WITH_TFM=y
|
||||
CONFIG_TFM_IPC=y
|
||||
CONFIG_TFM_PARTITION_AUDIT_LOG=n
|
||||
CONFIG_FPU=y
|
||||
CONFIG_FPU_SHARING=y
|
148
tests/arch/arm/arm_thread_swap_tz/src/main.c
Normal file
148
tests/arch/arm/arm_thread_swap_tz/src/main.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ztest.h>
|
||||
#include <psa/crypto.h>
|
||||
#include <kernel.h>
|
||||
|
||||
#ifndef EXC_RETURN_S
|
||||
/* bit [6] stack used to push registers: 0=Non-secure 1=Secure */
|
||||
#define EXC_RETURN_S (0x00000040UL)
|
||||
#endif
|
||||
|
||||
#define HASH_LEN 32
|
||||
|
||||
static struct k_work_delayable interrupting_work;
|
||||
static volatile bool work_done;
|
||||
static char dummy_string[0x1000];
|
||||
static char dummy_digest_correct[HASH_LEN];
|
||||
static const uint32_t delay_ms = 4;
|
||||
static volatile const struct k_thread *main_thread;
|
||||
|
||||
static void do_hash(char *hash)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
/* Calculate correct hash. */
|
||||
psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, dummy_string,
|
||||
sizeof(dummy_string), hash, HASH_LEN, &len);
|
||||
|
||||
zassert_equal(PSA_SUCCESS, status, NULL);
|
||||
zassert_equal(HASH_LEN, len, NULL);
|
||||
}
|
||||
|
||||
static void work_func(struct k_work *work)
|
||||
{
|
||||
#ifdef CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS
|
||||
/* Check that the main thread was executing in secure mode. */
|
||||
zassert_true(main_thread->arch.mode_exc_return & EXC_RETURN_S,
|
||||
"EXC_RETURN not secure: 0x%x\n", main_thread->arch.mode_exc_return);
|
||||
|
||||
#else
|
||||
/* Check that the main thread was executing in nonsecure mode. */
|
||||
zassert_false(main_thread->arch.mode_exc_return & EXC_RETURN_S,
|
||||
"EXC_RETURN not nonsecure: 0x%x\n", main_thread->arch.mode_exc_return);
|
||||
#endif
|
||||
|
||||
work_done = true;
|
||||
|
||||
/* If FPU is available, clobber FPU context in this thread to check that
|
||||
* the correct context is restored in the other thread.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_HAS_FPU
|
||||
uint32_t clobber_val[16] = {
|
||||
0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
|
||||
0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
|
||||
0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
|
||||
0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
|
||||
};
|
||||
|
||||
__asm__ volatile(
|
||||
"vldmia %0, {s0-s15}\n"
|
||||
"vldmia %0, {s16-s31}\n"
|
||||
:: "r" (clobber_val) :
|
||||
);
|
||||
#endif /* CONFIG_CPU_HAS_FPU */
|
||||
|
||||
/* Call a secure service here as well, to test the added complexity of
|
||||
* calling secure services from two threads.
|
||||
*/
|
||||
psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string,
|
||||
sizeof(dummy_string), dummy_digest_correct, HASH_LEN);
|
||||
|
||||
zassert_equal(PSA_SUCCESS, status, NULL);
|
||||
}
|
||||
|
||||
void test_thread_swap(void)
|
||||
{
|
||||
int err;
|
||||
char dummy_digest[HASH_LEN];
|
||||
k_timeout_t delay = K_MSEC(delay_ms);
|
||||
k_tid_t curr;
|
||||
psa_status_t status;
|
||||
|
||||
curr = k_current_get();
|
||||
main_thread = (struct k_thread *)curr;
|
||||
|
||||
status = psa_crypto_init();
|
||||
zassert_equal(PSA_SUCCESS, status, NULL);
|
||||
|
||||
/* Calculate correct hash. */
|
||||
do_hash(dummy_digest_correct);
|
||||
|
||||
/* Set up interrupting_work to fire while call_tfm() is executing.
|
||||
* This tests that it is safe to switch threads while a secure service
|
||||
* is running.
|
||||
*/
|
||||
k_work_init_delayable(&interrupting_work, work_func);
|
||||
|
||||
err = k_work_reschedule(&interrupting_work, delay);
|
||||
zassert_equal(1, err, "k_work_reschedule failed: %d\n", err);
|
||||
|
||||
/* If FPU is available, check that FPU context is preserved when calling
|
||||
* a secure function.
|
||||
*/
|
||||
#ifdef CONFIG_CPU_HAS_FPU
|
||||
uint32_t test_val[16] = {
|
||||
0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d,
|
||||
0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d,
|
||||
0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d,
|
||||
0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d, 0x1a2b3c4d,
|
||||
};
|
||||
uint32_t test_val_res0[16];
|
||||
uint32_t test_val_res1[16];
|
||||
|
||||
__asm__ volatile(
|
||||
"vldmia %0, {s0-s15}\n"
|
||||
"vldmia %0, {s16-s31}\n"
|
||||
:: "r" (test_val) :
|
||||
);
|
||||
#endif /* CONFIG_CPU_HAS_FPU */
|
||||
|
||||
work_done = false;
|
||||
do_hash(dummy_digest);
|
||||
zassert_true(work_done, "Interrupting work never happened\n");
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_FPU
|
||||
__asm__ volatile(
|
||||
"vstmia %0, {s0-s15}\n"
|
||||
"vstmia %1, {s16-s31}\n"
|
||||
:: "r" (test_val_res0), "r" (test_val_res1) :
|
||||
);
|
||||
|
||||
zassert_mem_equal(dummy_digest, dummy_digest_correct, HASH_LEN, NULL);
|
||||
zassert_mem_equal(test_val, test_val_res0, sizeof(test_val), NULL);
|
||||
zassert_mem_equal(test_val, test_val_res1, sizeof(test_val), NULL);
|
||||
#endif /* CONFIG_CPU_HAS_FPU */
|
||||
}
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
ztest_test_suite(test_thread_swap,
|
||||
ztest_unit_test(test_thread_swap)
|
||||
);
|
||||
ztest_run_test_suite(test_thread_swap);
|
||||
}
|
9
tests/arch/arm/arm_thread_swap_tz/testcase.yaml
Normal file
9
tests/arch/arm/arm_thread_swap_tz/testcase.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
common:
|
||||
filter: (CONFIG_TFM_BOARD != "") and CONFIG_ARM_NONSECURE_FIRMWARE
|
||||
tags: arm
|
||||
arch_allow: arm
|
||||
tests:
|
||||
arch.arm.swap.tz: {}
|
||||
arch.arm.swap.tz_off:
|
||||
extra_configs:
|
||||
- CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS=n
|
Loading…
Add table
Add a link
Reference in a new issue