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