1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 * Copyright (c) 2024 Intel Corporation
4 *
5 * This program and the accompanying materials are made available under the
6 * terms of the MIT License which is available at
7 * https://opensource.org/licenses/MIT.
8 *
9 * SPDX-License-Identifier: MIT
10 **************************************************************************/
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** Thread-Metric Component */
16 /** */
17 /** Porting Layer (Must be completed with RTOS specifics) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 /* Include necessary files. */
23
24 #include "tm_api.h"
25
26 #include <zephyr/kernel.h>
27
28 #define TM_TEST_NUM_THREADS 10
29 #define TM_TEST_STACK_SIZE 1024
30 #define TM_TEST_NUM_SEMAPHORES 4
31 #define TM_TEST_NUM_MESSAGE_QUEUES 4
32 #define TM_TEST_NUM_SLABS 4
33
34 #if (CONFIG_MP_MAX_NUM_CPUS > 1)
35 #error "*** Tests are only designed for single processor systems! ***"
36 #endif
37
38 static struct k_thread test_thread[TM_TEST_NUM_THREADS];
39 static K_THREAD_STACK_ARRAY_DEFINE(test_stack, TM_TEST_NUM_THREADS, TM_TEST_STACK_SIZE);
40
41 static struct k_sem test_sem[TM_TEST_NUM_SEMAPHORES];
42
43 static struct k_msgq test_msgq[TM_TEST_NUM_MESSAGE_QUEUES];
44 static char test_msgq_buffer[TM_TEST_NUM_MESSAGE_QUEUES][8][16];
45
46 static struct k_mem_slab test_slab[TM_TEST_NUM_SLABS];
47 static char __aligned(4) test_slab_buffer[TM_TEST_NUM_SLABS][8 * 128];
48
49 /*
50 * This function called from main performs basic RTOS initialization,
51 * calls the test initialization function, and then starts the RTOS function.
52 */
tm_initialize(void (* test_initialization_function)(void))53 void tm_initialize(void (*test_initialization_function)(void))
54 {
55 test_initialization_function();
56 }
57
58 /*
59 * This function takes a thread ID and priority and attempts to create the
60 * file in the underlying RTOS. Valid priorities range from 1 through 31,
61 * where 1 is the highest priority and 31 is the lowest. If successful,
62 * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
63 */
tm_thread_create(int thread_id,int priority,void (* entry_function)(void *,void *,void *))64 int tm_thread_create(int thread_id, int priority, void (*entry_function)(void *, void *, void *))
65 {
66 k_tid_t tid;
67
68 tid = k_thread_create(&test_thread[thread_id], test_stack[thread_id],
69 TM_TEST_STACK_SIZE, entry_function,
70 NULL, NULL, NULL, priority, 0, K_FOREVER);
71
72 /* Thread started in sleeping state. Switch to suspended state */
73
74 k_thread_suspend(&test_thread[thread_id]);
75 k_wakeup(&test_thread[thread_id]);
76
77 return (tid == &test_thread[thread_id]) ? TM_SUCCESS : TM_ERROR;
78 }
79
80 /*
81 * This function resumes the specified thread. If successful, the function should
82 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
83 */
tm_thread_resume(int thread_id)84 int tm_thread_resume(int thread_id)
85 {
86 k_thread_resume(&test_thread[thread_id]);
87
88 return TM_SUCCESS;
89 }
90
91 /*
92 * This function suspends the specified thread. If successful, the function should
93 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
94 */
tm_thread_suspend(int thread_id)95 int tm_thread_suspend(int thread_id)
96 {
97 k_thread_suspend(&test_thread[thread_id]);
98
99 return TM_SUCCESS;
100 }
101
102 /*
103 * This function relinquishes to other ready threads at the same
104 * priority.
105 */
tm_thread_relinquish(void)106 void tm_thread_relinquish(void)
107 {
108 k_yield();
109 }
110
111 /*
112 * This function suspends the specified thread for the specified number
113 * of seconds.
114 */
tm_thread_sleep(int seconds)115 void tm_thread_sleep(int seconds)
116 {
117 k_sleep(K_SECONDS(seconds));
118 }
119
120 /*
121 * This function creates the specified queue. If successful, the function should
122 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
123 */
tm_queue_create(int queue_id)124 int tm_queue_create(int queue_id)
125 {
126 k_msgq_init(&test_msgq[queue_id], &test_msgq_buffer[queue_id][0][0], 16, 8);
127
128 return TM_SUCCESS;
129 }
130
131 /*
132 * This function sends a 16-byte message to the specified queue. If successful,
133 * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
134 */
tm_queue_send(int queue_id,unsigned long * message_ptr)135 int tm_queue_send(int queue_id, unsigned long *message_ptr)
136 {
137 return k_msgq_put(&test_msgq[queue_id], message_ptr, K_FOREVER);
138 }
139
140 /*
141 * This function receives a 16-byte message from the specified queue. If successful,
142 * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
143 */
tm_queue_receive(int queue_id,unsigned long * message_ptr)144 int tm_queue_receive(int queue_id, unsigned long *message_ptr)
145 {
146 return k_msgq_get(&test_msgq[queue_id], message_ptr, K_FOREVER);
147 }
148
149 /*
150 * This function creates the specified semaphore. If successful, the function should
151 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
152 */
tm_semaphore_create(int semaphore_id)153 int tm_semaphore_create(int semaphore_id)
154 {
155 /* Create an available semaphore with max count of 1 */
156 return k_sem_init(&test_sem[semaphore_id], 1, 1);
157 }
158
159 /*
160 * This function gets the specified semaphore. If successful, the function should
161 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
162 */
tm_semaphore_get(int semaphore_id)163 int tm_semaphore_get(int semaphore_id)
164 {
165 return k_sem_take(&test_sem[semaphore_id], K_NO_WAIT);
166 }
167
168 /*
169 * This function puts the specified semaphore. If successful, the function should
170 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
171 */
tm_semaphore_put(int semaphore_id)172 int tm_semaphore_put(int semaphore_id)
173 {
174 k_sem_give(&test_sem[semaphore_id]);
175 return TM_SUCCESS;
176 }
177
178 /* This function is defined by the benchmark. */
179 extern void tm_interrupt_handler(const void *);
180
tm_cause_interrupt(void)181 void tm_cause_interrupt(void)
182 {
183 irq_offload(tm_interrupt_handler, NULL);
184 }
185
186 /*
187 * This function creates the specified memory pool that can support one or more
188 * allocations of 128 bytes. If successful, the function should
189 * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
190 */
tm_memory_pool_create(int pool_id)191 int tm_memory_pool_create(int pool_id)
192 {
193 int status;
194
195 status = k_mem_slab_init(&test_slab[pool_id], &test_slab_buffer[pool_id][0], 128, 8);
196
197 return (status == 0) ? TM_SUCCESS : TM_ERROR;
198 }
199
200 /*
201 * This function allocates a 128 byte block from the specified memory pool.
202 * If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
203 * should be returned.
204 */
tm_memory_pool_allocate(int pool_id,unsigned char ** memory_ptr)205 int tm_memory_pool_allocate(int pool_id, unsigned char **memory_ptr)
206 {
207 int status;
208
209 status = k_mem_slab_alloc(&test_slab[pool_id], (void **)memory_ptr, K_NO_WAIT);
210
211 return (status == 0) ? TM_SUCCESS : TM_ERROR;
212 }
213
214 /*
215 * This function releases a previously allocated 128 byte block from the specified
216 * memory pool. If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
217 * should be returned.
218 */
tm_memory_pool_deallocate(int pool_id,unsigned char * memory_ptr)219 int tm_memory_pool_deallocate(int pool_id, unsigned char *memory_ptr)
220 {
221 k_mem_slab_free(&test_slab[pool_id], (void *)memory_ptr);
222
223 return TM_SUCCESS;
224 }
225