23e7bc64b83336e4d3ada1f3cf4c305919e9988a
[fw/openocd] / src / rtos / embKernel.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2011 by Broadcom Corporation                            *
5  *   Evan Hunter - ehunter@broadcom.com                                    *
6  ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos_embkernel_stackings.h"
20
21 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
22
23 static bool embkernel_detect_rtos(struct target *target);
24 static int embkernel_create(struct target *target);
25 static int embkernel_update_threads(struct rtos *rtos);
26 static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
27                 struct rtos_reg **reg_list, int *num_regs);
28 static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
29
30 struct rtos_type embkernel_rtos = {
31                 .name = "embKernel",
32                 .detect_rtos = embkernel_detect_rtos,
33                 .create = embkernel_create,
34                 .update_threads = embkernel_update_threads,
35                 .get_thread_reg_list =
36                 embkernel_get_thread_reg_list,
37                 .get_symbol_list_to_lookup = embkernel_get_symbol_list_to_lookup,
38 };
39
40 enum {
41         SYMBOL_ID_S_CURRENT_TASK = 0,
42         SYMBOL_ID_S_LIST_READY = 1,
43         SYMBOL_ID_S_LIST_SLEEP = 2,
44         SYMBOL_ID_S_LIST_SUSPENDED = 3,
45         SYMBOL_ID_S_MAX_PRIORITIES = 4,
46         SYMBOL_ID_S_CURRENT_TASK_COUNT = 5,
47 };
48
49 static const char * const embkernel_symbol_list[] = {
50                 "Rtos::sCurrentTask",
51                 "Rtos::sListReady",
52                 "Rtos::sListSleep",
53                 "Rtos::sListSuspended",
54                 "Rtos::sMaxPriorities",
55                 "Rtos::sCurrentTaskCount",
56                 NULL };
57
58 struct embkernel_params {
59         const char *target_name;
60         const unsigned char pointer_width;
61         const unsigned char thread_count_width;
62         const unsigned char rtos_list_size;
63         const unsigned char thread_stack_offset;
64         const unsigned char thread_name_offset;
65         const unsigned char thread_priority_offset;
66         const unsigned char thread_priority_width;
67         const unsigned char iterable_next_offset;
68         const unsigned char iterable_task_owner_offset;
69         const struct rtos_register_stacking *stacking_info;
70 };
71
72 static const struct embkernel_params embkernel_params_list[] = {
73                 {
74                         "cortex_m", /* target_name */
75                         4, /* pointer_width */
76                         4, /* thread_count_width */
77                         8, /*rtos_list_size */
78                         0, /*thread_stack_offset */
79                         4, /*thread_name_offset */
80                         8, /*thread_priority_offset */
81                         4, /*thread_priority_width */
82                         4, /*iterable_next_offset */
83                         12, /*iterable_task_owner_offset */
84                         &rtos_embkernel_cortex_m_stacking, /* stacking_info*/
85                 },
86                 { "hla_target", /* target_name */
87                         4, /* pointer_width */
88                         4, /* thread_count_width */
89                         8, /*rtos_list_size */
90                         0, /*thread_stack_offset */
91                         4, /*thread_name_offset */
92                         8, /*thread_priority_offset */
93                         4, /*thread_priority_width */
94                         4, /*iterable_next_offset */
95                         12, /*iterable_task_owner_offset */
96                         &rtos_embkernel_cortex_m_stacking, /* stacking_info */
97                 }
98 };
99
100 static bool embkernel_detect_rtos(struct target *target)
101 {
102         if (target->rtos->symbols) {
103                 if (target->rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address != 0)
104                         return true;
105         }
106         return false;
107 }
108
109 static int embkernel_create(struct target *target)
110 {
111         size_t i = 0;
112         while ((i < ARRAY_SIZE(embkernel_params_list)) &&
113                         (strcmp(embkernel_params_list[i].target_name, target->type->name) != 0))
114                 i++;
115
116         if (i >= ARRAY_SIZE(embkernel_params_list)) {
117                 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
118                                 "list", target->type->name);
119                 return -1;
120         }
121
122         target->rtos->rtos_specific_params = (void *) &embkernel_params_list[i];
123         return 0;
124 }
125
126 static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param,
127                 struct thread_detail *details, const char *state_str)
128 {
129         int64_t task = 0;
130         int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
131                         (uint8_t *) &task);
132         if (retval != ERROR_OK)
133                 return retval;
134         details->threadid = (threadid_t) task;
135         details->exists = true;
136
137         int64_t name_ptr = 0;
138         retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
139                         (uint8_t *) &name_ptr);
140         if (retval != ERROR_OK)
141                 return retval;
142
143         details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
144         if (name_ptr) {
145                 retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
146                                 (uint8_t *) details->thread_name_str);
147                 if (retval != ERROR_OK)
148                         return retval;
149                 details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
150         } else {
151                 snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
152         }
153
154         int64_t priority = 0;
155         retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
156                         (uint8_t *) &priority);
157         if (retval != ERROR_OK)
158                 return retval;
159         details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
160         if (task == rtos->current_thread) {
161                 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u",
162                                 (unsigned int) priority);
163         } else {
164                 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u",
165                                 state_str, (unsigned int) priority);
166         }
167
168         LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
169                         (unsigned int)task, details->thread_name_str);
170         return 0;
171 }
172
173 static int embkernel_update_threads(struct rtos *rtos)
174 {
175         /* int i = 0; */
176         int retval;
177         const struct embkernel_params *param;
178
179         if (!rtos)
180                 return -1;
181
182         if (!rtos->rtos_specific_params)
183                 return -3;
184
185         if (!rtos->symbols) {
186                 LOG_ERROR("No symbols for embKernel");
187                 return -4;
188         }
189
190         if (rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address == 0) {
191                 LOG_ERROR("Don't have the thread list head");
192                 return -2;
193         }
194
195         /* wipe out previous thread details if any */
196         rtos_free_threadlist(rtos);
197
198         param = (const struct embkernel_params *) rtos->rtos_specific_params;
199
200         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK].address, param->pointer_width,
201                         (uint8_t *) &rtos->current_thread);
202         if (retval != ERROR_OK) {
203                 LOG_ERROR("Error reading current thread in embKernel thread list");
204                 return retval;
205         }
206
207         int64_t max_used_priority = 0;
208         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_MAX_PRIORITIES].address, param->pointer_width,
209                         (uint8_t *) &max_used_priority);
210         if (retval != ERROR_OK)
211                 return retval;
212
213         int thread_list_size = 0;
214         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_CURRENT_TASK_COUNT].address,
215                         param->thread_count_width, (uint8_t *) &thread_list_size);
216
217         if (retval != ERROR_OK) {
218                 LOG_ERROR("Could not read embKernel thread count from target");
219                 return retval;
220         }
221
222         /* create space for new thread details */
223         rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
224         if (!rtos->thread_details) {
225                 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
226                 return ERROR_FAIL;
227         }
228
229         int thread_idx = 0;
230         /* Look for ready tasks */
231         for (int pri = 0; pri < max_used_priority; pri++) {
232                 /* Get first item in queue */
233                 int64_t iterable = 0;
234                 retval = target_read_buffer(rtos->target,
235                                 rtos->symbols[SYMBOL_ID_S_LIST_READY].address + (pri * param->rtos_list_size), param->pointer_width,
236                                 (uint8_t *) &iterable);
237                 if (retval != ERROR_OK)
238                         return retval;
239                 for (; iterable && thread_idx < thread_list_size; thread_idx++) {
240                         /* Get info from this iterable item */
241                         retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Ready");
242                         if (retval != ERROR_OK)
243                                 return retval;
244                         /* Get next iterable item */
245                         retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
246                                         (uint8_t *) &iterable);
247                         if (retval != ERROR_OK)
248                                 return retval;
249                 }
250         }
251         /* Look for sleeping tasks */
252         int64_t iterable = 0;
253         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SLEEP].address, param->pointer_width,
254                         (uint8_t *) &iterable);
255         if (retval != ERROR_OK)
256                 return retval;
257         for (; iterable && thread_idx < thread_list_size; thread_idx++) {
258                 /*Get info from this iterable item */
259                 retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Sleeping");
260                 if (retval != ERROR_OK)
261                         return retval;
262                 /*Get next iterable item */
263                 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
264                                 (uint8_t *) &iterable);
265                 if (retval != ERROR_OK)
266                         return retval;
267         }
268
269         /* Look for suspended tasks  */
270         iterable = 0;
271         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_S_LIST_SUSPENDED].address, param->pointer_width,
272                         (uint8_t *) &iterable);
273         if (retval != ERROR_OK)
274                 return retval;
275         for (; iterable && thread_idx < thread_list_size; thread_idx++) {
276                 /* Get info from this iterable item */
277                 retval = embkernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[thread_idx], "Suspended");
278                 if (retval != ERROR_OK)
279                         return retval;
280                 /*Get next iterable item */
281                 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
282                                 (uint8_t *) &iterable);
283                 if (retval != ERROR_OK)
284                         return retval;
285         }
286
287         rtos->thread_count = 0;
288         rtos->thread_count = thread_idx;
289         LOG_OUTPUT("Found %u tasks\n", (unsigned int)thread_idx);
290         return 0;
291 }
292
293 static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
294                 struct rtos_reg **reg_list, int *num_regs)
295 {
296         int retval;
297         const struct embkernel_params *param;
298         int64_t stack_ptr = 0;
299
300         if (!rtos)
301                 return -1;
302
303         if (thread_id == 0)
304                 return -2;
305
306         if (!rtos->rtos_specific_params)
307                 return -1;
308
309         param = (const struct embkernel_params *) rtos->rtos_specific_params;
310
311         /* Read the stack pointer */
312         retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
313                         (uint8_t *) &stack_ptr);
314         if (retval != ERROR_OK) {
315                 LOG_ERROR("Error reading stack frame from embKernel thread");
316                 return retval;
317         }
318
319         return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
320 }
321
322 static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
323 {
324         unsigned int i;
325         *symbol_list = calloc(ARRAY_SIZE(embkernel_symbol_list), sizeof(struct symbol_table_elem));
326
327         for (i = 0; i < ARRAY_SIZE(embkernel_symbol_list); i++)
328                 (*symbol_list)[i].symbol_name = embkernel_symbol_list[i];
329
330         return 0;
331 }