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