1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * @file
9  * @brief Use stack API's in different scenarios
10  *
11  * This module tests following three basic scenarios:
12  *
13  * Scenario #1
14  * Test thread enters items into a stack, starts the Child thread and
15  * waits for a semaphore. Child thread extracts all items from the stack
16  * and enters some items back into the stack. Child thread gives the
17  * semaphore for Test thread to continue. Once the control is returned
18  * back to Test thread, it extracts all items from the stack.
19  *
20  * Scenario #2
21  * Test thread enters an item into stack2, starts a Child thread and
22  * extract an item from stack1 once the item is there. The child thread
23  * will extract an item from stack2 once the item is there and and enter
24  * an item to stack1. The flow of control goes from Test thread to Child
25  * thread and so forth.
26  *
27  * Scenario #3
28  * Tests the ISR interfaces. Test thread pushes items into stack2 and gives
29  * control to the Child thread. Child thread pops items from stack2 and then
30  * pushes items into stack1. Child thread gives back control to the Test thread
31  * and Test thread pops the items from stack1.
32  * All the Push and Pop operations happen in ISR Context.
33  */
34 
35 
36 /**
37  * @brief Tests for Kernel stack objects
38  * @defgroup kernel_stack_tests Stacks
39  * @ingroup all_tests
40  * @{
41  * @}
42  */
43 
44 #include <zephyr/ztest.h>
45 #include <zephyr/irq_offload.h>
46 
47 #define TSTACK_SIZE     (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
48 #define STACK_LEN       4
49 
50 /* stack objects used in this test */
51 K_STACK_DEFINE(stack1, STACK_LEN);
52 K_STACK_DEFINE(stack2, STACK_LEN);
53 
54 /* thread info * */
55 K_THREAD_STACK_DEFINE(threadstack, TSTACK_SIZE);
56 struct k_thread thread_data;
57 
58 /* Data pushed to stack */
59 static ZTEST_DMEM stack_data_t data1[STACK_LEN] = { 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD };
60 static ZTEST_DMEM stack_data_t data2[STACK_LEN] = { 0x1111, 0x2222, 0x3333, 0x4444 };
61 static ZTEST_DMEM stack_data_t data_isr[STACK_LEN] = { 0xABCD, 0xABCD, 0xABCD,
62 						       0xABCD };
63 
64 /* semaphore to sync threads */
65 static struct k_sem end_sema;
66 
67 
68 
69 K_HEAP_DEFINE(test_pool, 128 * 3);
70 
71 extern struct k_stack kstack;
72 extern struct k_stack stack;
73 extern struct k_sem end_sema;
74 
75 /* entry of contexts */
tIsr_entry_push(const void * p)76 static void tIsr_entry_push(const void *p)
77 {
78 	uint32_t i;
79 
80 	/* Push items to stack */
81 	for (i = 0U; i < STACK_LEN; i++) {
82 		k_stack_push((struct k_stack *)p, data_isr[i]);
83 	}
84 }
85 
tIsr_entry_pop(const void * p)86 static void tIsr_entry_pop(const void *p)
87 {
88 	uint32_t i;
89 
90 	/* Pop items from stack */
91 	for (i = 0U; i < STACK_LEN; i++) {
92 		if (p == &stack1) {
93 			k_stack_pop((struct k_stack *)p, &data1[i], K_NO_WAIT);
94 		} else {
95 			k_stack_pop((struct k_stack *)p, &data2[i], K_NO_WAIT);
96 		}
97 	}
98 }
99 
thread_entry_fn_single(void * p1,void * p2,void * p3)100 static void thread_entry_fn_single(void *p1, void *p2, void *p3)
101 {
102 	stack_data_t tmp[STACK_LEN];
103 	uint32_t i;
104 
105 	/* Pop items from stack */
106 	for (i = STACK_LEN; i; i--) {
107 		k_stack_pop((struct k_stack *)p1, &tmp[i - 1], K_NO_WAIT);
108 	}
109 	zassert_false(memcmp(tmp, data1, sizeof(tmp)),
110 		      "Push & Pop items does not match");
111 
112 	/* Push items from stack */
113 	for (i = 0U; i < STACK_LEN; i++) {
114 		k_stack_push((struct k_stack *)p1, data2[i]);
115 	}
116 
117 	/* Give control back to Test thread */
118 	k_sem_give(&end_sema);
119 }
120 
thread_entry_fn_dual(void * p1,void * p2,void * p3)121 static void thread_entry_fn_dual(void *p1, void *p2, void *p3)
122 {
123 	stack_data_t tmp[STACK_LEN];
124 	uint32_t i;
125 
126 	for (i = 0U; i < STACK_LEN; i++) {
127 		/* Pop items from stack2 */
128 		k_stack_pop(p2, &tmp[i], K_FOREVER);
129 
130 		/* Push items to stack1 */
131 		k_stack_push(p1, data1[i]);
132 
133 	}
134 	zassert_false(memcmp(tmp, data2, sizeof(tmp)),
135 		      "Push & Pop items does not match");
136 }
137 
thread_entry_fn_isr(void * p1,void * p2,void * p3)138 static void thread_entry_fn_isr(void *p1, void *p2, void *p3)
139 {
140 	/* Pop items from stack2 */
141 	irq_offload(tIsr_entry_pop, (const void *)p2);
142 	zassert_false(memcmp(data_isr, data2, sizeof(data_isr)),
143 		      "Push & Pop items does not match");
144 
145 	/* Push items to stack1 */
146 	irq_offload(tIsr_entry_push, (const void *)p1);
147 
148 	/* Give control back to Test thread */
149 	k_sem_give(&end_sema);
150 }
151 
152 /**
153  * @addtogroup kernel_stack_tests
154  * @{
155  */
156 
157 /**
158  * @brief Verify data passing between threads using single stack
159  * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
160  */
ZTEST_USER(stack_usage,test_single_stack_play)161 ZTEST_USER(stack_usage, test_single_stack_play)
162 {
163 	stack_data_t tmp[STACK_LEN];
164 	uint32_t i;
165 
166 	/* Init kernel objects */
167 	k_sem_init(&end_sema, 0, 1);
168 
169 	/* Push items to stack */
170 	for (i = 0U; i < STACK_LEN; i++) {
171 		k_stack_push(&stack1, data1[i]);
172 	}
173 
174 	k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
175 				      thread_entry_fn_single, &stack1, NULL,
176 				      NULL, K_PRIO_PREEMPT(0), K_USER |
177 				      K_INHERIT_PERMS, K_NO_WAIT);
178 
179 	/* Let the child thread run */
180 	k_sem_take(&end_sema, K_FOREVER);
181 
182 	/* Pop items from stack */
183 	for (i = STACK_LEN; i; i--) {
184 		k_stack_pop(&stack1, &tmp[i - 1], K_NO_WAIT);
185 	}
186 
187 	zassert_false(memcmp(tmp, data2, sizeof(tmp)),
188 		      "Push & Pop items does not match");
189 
190 	/* Clear the spawn thread to avoid side effect */
191 	k_thread_abort(tid);
192 }
193 
194 /**
195  * @brief Verify data passing between threads using dual stack
196  * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
197  */
ZTEST_USER(stack_usage_1cpu,test_dual_stack_play)198 ZTEST_USER(stack_usage_1cpu, test_dual_stack_play)
199 {
200 	stack_data_t tmp[STACK_LEN];
201 	uint32_t i;
202 
203 	k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
204 				      thread_entry_fn_dual, &stack1, &stack2,
205 				      NULL, K_PRIO_PREEMPT(0), K_USER |
206 				      K_INHERIT_PERMS, K_NO_WAIT);
207 
208 	for (i = 0U; i < STACK_LEN; i++) {
209 		/* Push items to stack2 */
210 		k_stack_push(&stack2, data2[i]);
211 
212 		/* Pop items from stack1 */
213 		k_stack_pop(&stack1, &tmp[i], K_FOREVER);
214 	}
215 
216 	zassert_false(memcmp(tmp, data1, sizeof(tmp)),
217 		      "Push & Pop items does not match");
218 
219 	/* Clear the spawn thread to avoid side effect */
220 	k_thread_abort(tid);
221 }
222 
223 /**
224  * @brief Verify data passing between thread and ISR
225  * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
226  */
ZTEST(stack_usage_1cpu,test_isr_stack_play)227 ZTEST(stack_usage_1cpu, test_isr_stack_play)
228 {
229 	/* Init kernel objects */
230 	k_sem_init(&end_sema, 0, 1);
231 
232 	k_tid_t tid = k_thread_create(&thread_data, threadstack, TSTACK_SIZE,
233 				      thread_entry_fn_isr, &stack1, &stack2,
234 				      NULL, K_PRIO_PREEMPT(0),
235 				      K_INHERIT_PERMS, K_NO_WAIT);
236 
237 
238 	/* Push items to stack2 */
239 	irq_offload(tIsr_entry_push, (const void *)&stack2);
240 
241 	/* Let the child thread run */
242 	k_sem_take(&end_sema, K_FOREVER);
243 
244 	/* Pop items from stack1 */
245 	irq_offload(tIsr_entry_pop, (const void *)&stack1);
246 
247 	zassert_false(memcmp(data_isr, data1, sizeof(data_isr)),
248 		      "Push & Pop items does not match");
249 
250 	/* Clear the spawn thread to avoid side effect */
251 	k_thread_abort(tid);
252 }
253 
254 /* the thread entry */
thread_entry_wait(void * p1,void * p2,void * p3)255 void thread_entry_wait(void *p1, void *p2, void *p3)
256 {
257 	stack_data_t *txdata = p3;
258 
259 	k_stack_push(p1, *(txdata + 2));
260 	k_stack_push(p1, *(txdata + 3));
261 }
262 
263 /**
264  * @brief Test that the stack pop can be waited
265  * if no item available
266  *
267  * @details Create and initialize a new stack
268  * Set two timeout parameters to indicate
269  * the maximum amount of time the thread will wait.
270  *
271  * @ingroup kernel_stack_tests
272  *
273  * @see k_stack_push(), #K_STACK_DEFINE(x), k_stack_pop()
274  */
ZTEST(stack_usage,test_stack_pop_can_wait)275 ZTEST(stack_usage, test_stack_pop_can_wait)
276 {
277 	struct k_stack stack3;
278 	stack_data_t tx_data[STACK_LEN] = { 0xaa, 0xbb, 0xcc, 0xdd };
279 	stack_data_t rx_data[STACK_LEN] = { 0 };
280 
281 	k_stack_alloc_init(&stack3, 2);
282 	k_tid_t tid = k_thread_create(&thread_data, threadstack,
283 			TSTACK_SIZE, thread_entry_wait, &stack3,
284 			NULL, tx_data, K_PRIO_PREEMPT(0), 0,
285 			K_NO_WAIT);
286 
287 	for (int i = 0; i < 2; i++) {
288 		k_stack_push(&stack3, tx_data[i]);
289 	}
290 
291 	for (int i = 0; i < 3; i++) {
292 		k_stack_pop(&stack3, &rx_data[i], K_FOREVER);
293 	}
294 
295 	zassert_true(rx_data[2] == tx_data[2], "wait forever and pop failed\n");
296 	k_stack_pop(&stack3, &rx_data[3], K_MSEC(50));
297 	zassert_true(rx_data[3] == tx_data[3], "Wait maximum time pop failed\n");
298 	/* Clear the spawn thread to avoid side effect */
299 	k_thread_abort(tid);
300 	/*free the buffer allocated*/
301 	k_stack_cleanup(&stack3);
302 }
303 
304 /**
305  * @}
306  */
307 
308 extern struct k_stack threadstack1;
309 extern struct k_thread thread_data1;
310 extern struct k_sem end_sema1;
311 
stack_setup(void)312 static void *stack_setup(void)
313 {
314 	k_thread_access_grant(k_current_get(), &stack1, &stack2, &thread_data,
315 			      &end_sema, &threadstack, &kstack, &stack, &thread_data1,
316 			      &end_sema1, &threadstack1);
317 
318 	k_thread_heap_assign(k_current_get(), &test_pool);
319 
320 	return NULL;
321 }
322 
323 ZTEST_SUITE(stack_usage, NULL, stack_setup, NULL, NULL, NULL);
324 
325 ZTEST_SUITE(stack_contexts, NULL, stack_setup, NULL, NULL, NULL);
326 
327 ZTEST_SUITE(stack_fail, NULL, stack_setup, NULL, NULL, NULL);
328 
329 ZTEST_SUITE(stack_usage_1cpu, NULL, stack_setup,
330 		ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
331