1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <psa/crypto.h>
9 #include <zephyr/kernel.h>
10
11 #ifndef EXC_RETURN_S
12 /* bit [6] stack used to push registers: 0=Non-secure 1=Secure */
13 #define EXC_RETURN_S (0x00000040UL)
14 #endif
15
16 #define HASH_LEN 32
17
18 static struct k_work_delayable interrupting_work;
19 static volatile bool work_done;
20 static char dummy_string[0x1000];
21 static char dummy_digest_correct[HASH_LEN];
22 static const uint32_t delay_ms = 1;
23 static volatile const struct k_thread *main_thread;
24
do_hash(char * hash)25 static void do_hash(char *hash)
26 {
27 size_t len;
28
29 /* Calculate correct hash. */
30 psa_status_t status = psa_hash_compute(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string),
31 hash, HASH_LEN, &len);
32
33 zassert_equal(PSA_SUCCESS, status, "psa_hash_compute_fail: %d\n", status);
34 zassert_equal(HASH_LEN, len, "hash length not correct\n");
35 }
36
work_func(struct k_work * work)37 static void work_func(struct k_work *work)
38 {
39 #ifdef CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS
40 /* Check that the main thread was executing in secure mode. */
41 zassert_true(main_thread->arch.mode_exc_return & EXC_RETURN_S,
42 "EXC_RETURN not secure: 0x%x\n", main_thread->arch.mode_exc_return);
43
44 #else
45 /* Check that the main thread was executing in nonsecure mode. */
46 zassert_false(main_thread->arch.mode_exc_return & EXC_RETURN_S,
47 "EXC_RETURN not nonsecure: 0x%x\n", main_thread->arch.mode_exc_return);
48 #endif
49
50 work_done = true;
51
52 /* If FPU is available, clobber FPU context in this thread to check that
53 * the correct context is restored in the other thread.
54 */
55 #ifdef CONFIG_CPU_HAS_FPU
56 uint32_t clobber_val[16] = {
57 0xdeadbee0, 0xdeadbee1, 0xdeadbee2, 0xdeadbee3, 0xdeadbee4, 0xdeadbee5,
58 0xdeadbee6, 0xdeadbee7, 0xdeadbee8, 0xdeadbee9, 0xdeadbeea, 0xdeadbeeb,
59 0xdeadbeec, 0xdeadbeed, 0xdeadbeee, 0xdeadbeef,
60 };
61
62 __asm__ volatile("vldmia %0, {s0-s15}\n"
63 "vldmia %0, {s16-s31}\n" ::"r"(clobber_val)
64 :);
65 #endif /* CONFIG_CPU_HAS_FPU */
66
67 /* Call a secure service here as well, to test the added complexity of
68 * calling secure services from two threads.
69 */
70 psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string, sizeof(dummy_string),
71 dummy_digest_correct, HASH_LEN);
72
73 zassert_equal(PSA_SUCCESS, status, "psa_hash_compare failed\n");
74 }
75
ZTEST(thread_swap_tz,test_thread_swap_tz)76 ZTEST(thread_swap_tz, test_thread_swap_tz)
77 {
78 int err;
79 char dummy_digest[HASH_LEN];
80 k_timeout_t delay = K_MSEC(delay_ms);
81 k_tid_t curr;
82 psa_status_t status;
83
84 curr = k_current_get();
85 main_thread = (struct k_thread *)curr;
86
87 status = psa_crypto_init();
88 zassert_equal(PSA_SUCCESS, status);
89
90 /* Calculate correct hash. */
91 do_hash(dummy_digest_correct);
92
93 /* Set up interrupting_work to fire while call_tfm() is executing.
94 * This tests that it is safe to switch threads while a secure service
95 * is running.
96 */
97 k_work_init_delayable(&interrupting_work, work_func);
98
99 err = k_work_reschedule(&interrupting_work, delay);
100 zassert_equal(1, err, "k_work_reschedule failed: %d\n", err);
101
102 /* If FPU is available, check that FPU context is preserved when calling
103 * a secure function.
104 */
105 #ifdef CONFIG_CPU_HAS_FPU
106 uint32_t test_val0[16] = {
107 0x1a2b3c40, 0x1a2b3c41, 0x1a2b3c42, 0x1a2b3c43, 0x1a2b3c44, 0x1a2b3c45,
108 0x1a2b3c46, 0x1a2b3c47, 0x1a2b3c48, 0x1a2b3c49, 0x1a2b3c4a, 0x1a2b3c4b,
109 0x1a2b3c4c, 0x1a2b3c4d, 0x1a2b3c4e, 0x1a2b3c4f,
110 };
111 uint32_t test_val1[16] = {
112 0x2b3c4d50, 0x2b3c4d51, 0x2b3c4d52, 0x2b3c4d53, 0x2b3c4d54, 0x2b3c4d55,
113 0x2b3c4d56, 0x2b3c4d57, 0x2b3c4d58, 0x2b3c4d59, 0x2b3c4d5a, 0x2b3c4d5b,
114 0x2b3c4d5c, 0x2b3c4d5d, 0x2b3c4d5e, 0x2b3c4d5f,
115 };
116 uint32_t test_val_res0[16];
117 uint32_t test_val_res1[16];
118
119 __asm__ volatile("vldmia %0, {s0-s15}\n"
120 "vldmia %1, {s16-s31}\n" ::"r"(test_val0),
121 "r"(test_val1)
122 :);
123
124 #endif /* CONFIG_CPU_HAS_FPU */
125
126 work_done = false;
127 do_hash(dummy_digest);
128 zassert_true(work_done, "Interrupting work never happened\n");
129
130 #ifdef CONFIG_CPU_HAS_FPU
131 __asm__ volatile("vstmia %0, {s0-s15}\n"
132 "vstmia %1, {s16-s31}\n" ::"r"(test_val_res0),
133 "r"(test_val_res1)
134 :);
135
136 zassert_mem_equal(dummy_digest, dummy_digest_correct, HASH_LEN, NULL);
137 zassert_mem_equal(test_val0, test_val_res0, sizeof(test_val0), NULL);
138 zassert_mem_equal(test_val1, test_val_res1, sizeof(test_val1), NULL);
139 #endif /* CONFIG_CPU_HAS_FPU */
140 }
141
142 ZTEST_SUITE(thread_swap_tz, NULL, NULL, NULL, NULL, NULL);
143