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,
31 sizeof(dummy_string), 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,
58 0xdeadbee4, 0xdeadbee5, 0xdeadbee6, 0xdeadbee7,
59 0xdeadbee8, 0xdeadbee9, 0xdeadbeea, 0xdeadbeeb,
60 0xdeadbeec, 0xdeadbeed, 0xdeadbeee, 0xdeadbeef,
61 };
62
63 __asm__ volatile(
64 "vldmia %0, {s0-s15}\n"
65 "vldmia %0, {s16-s31}\n"
66 :: "r" (clobber_val) :
67 );
68 #endif /* CONFIG_CPU_HAS_FPU */
69
70 /* Call a secure service here as well, to test the added complexity of
71 * calling secure services from two threads.
72 */
73 psa_status_t status = psa_hash_compare(PSA_ALG_SHA_256, dummy_string,
74 sizeof(dummy_string), dummy_digest_correct, HASH_LEN);
75
76 zassert_equal(PSA_SUCCESS, status, "psa_hash_compare failed\n");
77
78 }
79
ZTEST(thread_swap_tz,test_thread_swap_tz)80 ZTEST(thread_swap_tz, test_thread_swap_tz)
81 {
82 int err;
83 char dummy_digest[HASH_LEN];
84 k_timeout_t delay = K_MSEC(delay_ms);
85 k_tid_t curr;
86 psa_status_t status;
87
88 curr = k_current_get();
89 main_thread = (struct k_thread *)curr;
90
91 status = psa_crypto_init();
92 zassert_equal(PSA_SUCCESS, status);
93
94 /* Calculate correct hash. */
95 do_hash(dummy_digest_correct);
96
97 /* Set up interrupting_work to fire while call_tfm() is executing.
98 * This tests that it is safe to switch threads while a secure service
99 * is running.
100 */
101 k_work_init_delayable(&interrupting_work, work_func);
102
103 err = k_work_reschedule(&interrupting_work, delay);
104 zassert_equal(1, err, "k_work_reschedule failed: %d\n", err);
105
106 /* If FPU is available, check that FPU context is preserved when calling
107 * a secure function.
108 */
109 #ifdef CONFIG_CPU_HAS_FPU
110 uint32_t test_val0[16] = {
111 0x1a2b3c40, 0x1a2b3c41, 0x1a2b3c42, 0x1a2b3c43,
112 0x1a2b3c44, 0x1a2b3c45, 0x1a2b3c46, 0x1a2b3c47,
113 0x1a2b3c48, 0x1a2b3c49, 0x1a2b3c4a, 0x1a2b3c4b,
114 0x1a2b3c4c, 0x1a2b3c4d, 0x1a2b3c4e, 0x1a2b3c4f,
115 };
116 uint32_t test_val1[16] = {
117 0x2b3c4d50, 0x2b3c4d51, 0x2b3c4d52, 0x2b3c4d53,
118 0x2b3c4d54, 0x2b3c4d55, 0x2b3c4d56, 0x2b3c4d57,
119 0x2b3c4d58, 0x2b3c4d59, 0x2b3c4d5a, 0x2b3c4d5b,
120 0x2b3c4d5c, 0x2b3c4d5d, 0x2b3c4d5e, 0x2b3c4d5f,
121 };
122 uint32_t test_val_res0[16];
123 uint32_t test_val_res1[16];
124
125 __asm__ volatile(
126 "vldmia %0, {s0-s15}\n"
127 "vldmia %1, {s16-s31}\n"
128 :: "r" (test_val0), "r" (test_val1) :
129 );
130
131 #endif /* CONFIG_CPU_HAS_FPU */
132
133 work_done = false;
134 do_hash(dummy_digest);
135 zassert_true(work_done, "Interrupting work never happened\n");
136
137 #ifdef CONFIG_CPU_HAS_FPU
138 __asm__ volatile(
139 "vstmia %0, {s0-s15}\n"
140 "vstmia %1, {s16-s31}\n"
141 :: "r" (test_val_res0), "r" (test_val_res1) :
142 );
143
144 zassert_mem_equal(dummy_digest, dummy_digest_correct, HASH_LEN, NULL);
145 zassert_mem_equal(test_val0, test_val_res0, sizeof(test_val0), NULL);
146 zassert_mem_equal(test_val1, test_val_res1, sizeof(test_val1), NULL);
147 #endif /* CONFIG_CPU_HAS_FPU */
148 }
149
150 ZTEST_SUITE(thread_swap_tz, NULL, NULL, NULL, NULL, NULL);
151