1 /*
2 * Copyright (c) 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/kernel_structs.h>
10 #include <zephyr/app_memory/app_memdomain.h>
11 #include <zephyr/sys/libc-hooks.h>
12 #include <zephyr/sys/util.h>
13
14 #define NUM_THREADS 3
15 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
16
17 #define STATIC_DATA8 0x7FU
18 #define STATIC_DATA32 0xABCDEF00U
19 #define STATIC_DATA64 0x1122334455667788UL
20
21 #define PREFIX_8 0x30U
22 #define PREFIX_32 0x44668800U
23 #define PREFIX_64 0xFFEEDDCC00000000UL
24
25 #ifdef CONFIG_USERSPACE
26 K_APPMEM_PARTITION_DEFINE(part_common);
27 struct k_mem_domain dom_common;
28 #endif /* CONFIG_USERSPACE */
29
30 enum test_result {
31 TEST_OK,
32
33 /* When thread_data* != STATIC_DATA at thread entry */
34 ERR_BAD_STATIC_DATA,
35
36 /* When thread_bss* != 0 at thread entry */
37 ERR_BSS_NOT_ZERO,
38
39 /* If data/bss is changed by other threads */
40 ERR_DATA_CHANGED_BY_OTHERS,
41 ERR_BSS_CHANGED_BY_OTHERS,
42
43 TEST_NOT_STARTED,
44 };
45
46 static K_THREAD_STACK_ARRAY_DEFINE(tls_stack, NUM_THREADS, STACK_SIZE);
47
48 static struct k_thread tls_thread[NUM_THREADS];
49
50 K_APP_BMEM(part_common) static k_tid_t tls_tid[NUM_THREADS];
51 K_APP_BMEM(part_common) static enum test_result tls_result[NUM_THREADS];
52
53 /* Thread data with initialized values */
54 static uint8_t Z_THREAD_LOCAL thread_data8 = STATIC_DATA8;
55 static uint32_t Z_THREAD_LOCAL thread_data32 = STATIC_DATA32;
56 static uint64_t Z_THREAD_LOCAL thread_data64 = STATIC_DATA64;
57
58 /* Zeroed thread data */
59 static uint8_t Z_THREAD_LOCAL thread_bss8;
60 static uint32_t Z_THREAD_LOCAL thread_bss32;
61 static uint64_t Z_THREAD_LOCAL thread_bss64;
62
tls_thread_entry(void * p1,void * p2,void * p3)63 static void tls_thread_entry(void *p1, void *p2, void *p3)
64 {
65 uint32_t idx;
66
67 idx = (uint32_t)POINTER_TO_UINT(p1);
68
69 /* Check if TLS area in stack is initialized correctly */
70 if (thread_data8 != STATIC_DATA8) {
71 tls_result[idx] = ERR_BAD_STATIC_DATA;
72 goto out;
73 }
74
75 if (thread_data32 != STATIC_DATA32) {
76 tls_result[idx] = ERR_BAD_STATIC_DATA;
77 goto out;
78 }
79
80 if (thread_data64 != STATIC_DATA64) {
81 tls_result[idx] = ERR_BAD_STATIC_DATA;
82 goto out;
83 }
84
85 if (thread_bss8 != 0) {
86 tls_result[idx] = ERR_BSS_NOT_ZERO;
87 goto out;
88 }
89
90 if (thread_bss32 != 0) {
91 tls_result[idx] = ERR_BSS_NOT_ZERO;
92 goto out;
93 }
94
95 if (thread_bss64 != 0) {
96 tls_result[idx] = ERR_BSS_NOT_ZERO;
97 goto out;
98 }
99
100 /* Set thread data and see if they remain unchanged */
101 thread_data8 = STATIC_DATA8 + idx;
102 thread_bss8 = PREFIX_8 + idx;
103
104 thread_data32 = STATIC_DATA32 + idx;
105 thread_bss32 = PREFIX_32 + idx;
106
107 thread_data64 = STATIC_DATA64 + idx;
108 thread_bss64 = PREFIX_64 + idx;
109
110 /* Let other threads run */
111 k_sleep(K_MSEC(100));
112
113 if (thread_data8 != (STATIC_DATA8 + idx)) {
114 tls_result[idx] = ERR_DATA_CHANGED_BY_OTHERS;
115 goto out;
116 }
117
118 if (thread_data32 != (STATIC_DATA32 + idx)) {
119 tls_result[idx] = ERR_DATA_CHANGED_BY_OTHERS;
120 goto out;
121 }
122
123 if (thread_data64 != (STATIC_DATA64 + idx)) {
124 tls_result[idx] = ERR_DATA_CHANGED_BY_OTHERS;
125 goto out;
126 }
127
128 if (thread_bss8 != (PREFIX_8 + idx)) {
129 tls_result[idx] = ERR_BSS_CHANGED_BY_OTHERS;
130 goto out;
131 }
132
133 if (thread_bss32 != (PREFIX_32 + idx)) {
134 tls_result[idx] = ERR_BSS_CHANGED_BY_OTHERS;
135 goto out;
136 }
137
138 if (thread_bss64 != (PREFIX_64 + idx)) {
139 tls_result[idx] = ERR_BSS_CHANGED_BY_OTHERS;
140 goto out;
141 }
142
143 /* Values are all expected. Test passed */
144 tls_result[idx] = TEST_OK;
145
146 out:
147 return;
148 }
149
start_tls_test(uint32_t thread_options)150 static void start_tls_test(uint32_t thread_options)
151 {
152 unsigned int i;
153 bool passed;
154
155 /* Create threads */
156 for (i = 0; i < NUM_THREADS; i++) {
157 tls_result[i] = TEST_NOT_STARTED;
158 tls_tid[i] = k_thread_create(&tls_thread[i], tls_stack[i],
159 STACK_SIZE, tls_thread_entry,
160 UINT_TO_POINTER(i), NULL, NULL,
161 0, thread_options, K_NO_WAIT);
162 }
163
164 /* Wait for all threads to run */
165 k_sleep(K_MSEC(500));
166
167 /* Stop all threads */
168 for (i = 0; i < NUM_THREADS; i++) {
169 k_thread_abort(tls_tid[i]);
170 k_thread_join(&tls_thread[i], K_FOREVER);
171 }
172
173 /* Check test results */
174 passed = true;
175 for (i = 0; i < NUM_THREADS; i++) {
176 TC_PRINT("thread %d: result %d (expecting %d)\n",
177 i, tls_result[i], TEST_OK);
178 if (tls_result[i] != TEST_OK) {
179 passed = false;
180 }
181 }
182
183 zassert_true(passed, "Test failed");
184 }
185
ZTEST(thread_tls,test_tls)186 ZTEST(thread_tls, test_tls)
187 {
188 if (IS_ENABLED(CONFIG_USERSPACE)) {
189 ztest_test_skip();
190 }
191
192 /* TLS test in supervisor mode */
193 start_tls_test(0);
194 }
195
ZTEST_USER(thread_tls,test_tls_userspace)196 ZTEST_USER(thread_tls, test_tls_userspace)
197 {
198 /* TLS test in supervisor mode */
199 start_tls_test(K_USER | K_INHERIT_PERMS);
200 }
201
thread_tls_setup(void)202 void *thread_tls_setup(void)
203 {
204 #ifdef CONFIG_USERSPACE
205 int ret;
206 unsigned int i;
207
208 struct k_mem_partition *parts[] = {
209 &part_common,
210 #if Z_LIBC_PARTITION_EXISTS
211 &z_libc_partition,
212 #endif
213 &ztest_mem_partition,
214 };
215
216 parts[0] = &part_common;
217
218 ret = k_mem_domain_init(&dom_common, ARRAY_SIZE(parts), parts);
219 __ASSERT(ret == 0, "k_mem_domain_init() failed %d", ret);
220 ARG_UNUSED(ret);
221
222 k_mem_domain_add_thread(&dom_common, k_current_get());
223
224 for (i = 0; i < NUM_THREADS; i++) {
225 k_thread_access_grant(k_current_get(),
226 &tls_thread[i], &tls_stack[i]);
227 }
228 #endif /* CONFIG_USERSPACE */
229
230 return NULL;
231 }
232
233 ZTEST_SUITE(thread_tls, NULL, thread_tls_setup, NULL, NULL, NULL);
234