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