Clean up const usage to avoid excessive casting
[openocd.git] / src / rtos / embKernel.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_embkernel_stackings.h"
33
34 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
35
36 static int embKernel_detect_rtos(struct target *target);
37 static int embKernel_create(struct target *target);
38 static int embKernel_update_threads(struct rtos *rtos);
39 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
40 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
41
42 struct rtos_type embKernel_rtos = {
43 .name = "embKernel",
44 .detect_rtos = embKernel_detect_rtos,
45 .create = embKernel_create,
46 .update_threads = embKernel_update_threads,
47 .get_thread_reg_list =
48 embKernel_get_thread_reg_list,
49 .get_symbol_list_to_lookup = embKernel_get_symbol_list_to_lookup,
50 };
51
52 enum {
53 SYMBOL_ID_sCurrentTask = 0,
54 SYMBOL_ID_sListReady = 1,
55 SYMBOL_ID_sListSleep = 2,
56 SYMBOL_ID_sListSuspended = 3,
57 SYMBOL_ID_sMaxPriorities = 4,
58 SYMBOL_ID_sCurrentTaskCount = 5,
59 };
60
61 static char *embKernel_symbol_list[] = {
62 "Rtos::sCurrentTask",
63 "Rtos::sListReady",
64 "Rtos::sListSleep",
65 "Rtos::sListSuspended",
66 "Rtos::sMaxPriorities",
67 "Rtos::sCurrentTaskCount",
68 NULL };
69
70 struct embKernel_params {
71 const char *target_name;
72 const unsigned char pointer_width;
73 const unsigned char thread_count_width;
74 const unsigned char rtos_list_size;
75 const unsigned char thread_stack_offset;
76 const unsigned char thread_name_offset;
77 const unsigned char thread_priority_offset;
78 const unsigned char thread_priority_width;
79 const unsigned char iterable_next_offset;
80 const unsigned char iterable_task_owner_offset;
81 const struct rtos_register_stacking *stacking_info;
82 };
83
84 struct embKernel_params embKernel_params_list[] = {
85 {
86 "cortex_m", /* 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 { "hla_target", /* target_name */
99 4, /* pointer_width */
100 4, /* thread_count_width */
101 8, /*rtos_list_size */
102 0, /*thread_stack_offset */
103 4, /*thread_name_offset */
104 8, /*thread_priority_offset */
105 4, /*thread_priority_width */
106 4, /*iterable_next_offset */
107 12, /*iterable_task_owner_offset */
108 &rtos_embkernel_Cortex_M_stacking, /* stacking_info */
109 }
110 };
111
112 static int embKernel_detect_rtos(struct target *target)
113 {
114 if (target->rtos->symbols != NULL) {
115 if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0)
116 return 1;
117 }
118 return 0;
119 }
120
121 static int embKernel_create(struct target *target)
122 {
123 size_t i = 0;
124 while ((i < ARRAY_SIZE(embKernel_params_list)) &&
125 (0 != strcmp(embKernel_params_list[i].target_name, target->type->name)))
126 i++;
127
128 if (i >= ARRAY_SIZE(embKernel_params_list)) {
129 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
130 "list", target->type->name);
131 return -1;
132 }
133
134 target->rtos->rtos_specific_params = &embKernel_params_list[i];
135 return 0;
136 }
137
138 static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
139 struct thread_detail *details, const char* state_str)
140 {
141 int64_t task = 0;
142 int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
143 (uint8_t *) &task);
144 if (retval != ERROR_OK)
145 return retval;
146 details->threadid = (threadid_t) task;
147 details->exists = true;
148 details->display_str = NULL;
149
150 int64_t name_ptr = 0;
151 retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
152 (uint8_t *) &name_ptr);
153 if (retval != ERROR_OK)
154 return retval;
155
156 details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
157 if (name_ptr) {
158 retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
159 (uint8_t *) details->thread_name_str);
160 if (retval != ERROR_OK)
161 return retval;
162 details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
163 } else {
164 snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
165 }
166
167 int64_t priority = 0;
168 retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
169 (uint8_t *) &priority);
170 if (retval != ERROR_OK)
171 return retval;
172 details->extra_info_str = (char *) malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
173 if (task == rtos->current_thread) {
174 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running",
175 (unsigned int) priority);
176 } else {
177 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority,
178 state_str);
179 }
180
181 LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
182 (unsigned int)task, details->thread_name_str);
183 return 0;
184 }
185
186 static int embKernel_update_threads(struct rtos *rtos)
187 {
188 /* int i = 0; */
189 int retval;
190 const struct embKernel_params *param;
191
192 if (rtos == NULL)
193 return -1;
194
195 if (rtos->rtos_specific_params == NULL)
196 return -3;
197
198 if (rtos->symbols == NULL) {
199 LOG_ERROR("No symbols for embKernel");
200 return -4;
201 }
202
203 if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) {
204 LOG_ERROR("Don't have the thread list head");
205 return -2;
206 }
207
208 /* wipe out previous thread details if any */
209 if (rtos->thread_details != NULL) {
210 int j;
211 for (j = 0; j < rtos->thread_count; j++) {
212 if (rtos->thread_details[j].display_str != NULL) {
213 free(rtos->thread_details[j].display_str);
214 rtos->thread_details[j].display_str = NULL;
215 }
216 if (rtos->thread_details[j].thread_name_str != NULL) {
217 free(rtos->thread_details[j].thread_name_str);
218 rtos->thread_details[j].thread_name_str = NULL;
219 }
220 if (rtos->thread_details[j].extra_info_str != NULL) {
221 free(rtos->thread_details[j].extra_info_str);
222 rtos->thread_details[j].extra_info_str = NULL;
223 }
224 }
225 free(rtos->thread_details);
226 rtos->thread_details = NULL;
227 }
228
229 param = (const struct embKernel_params *) rtos->rtos_specific_params;
230
231 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
232 (uint8_t *) &rtos->current_thread);
233 if (retval != ERROR_OK) {
234 LOG_ERROR("Error reading current thread in embKernel thread list");
235 return retval;
236 }
237
238 int64_t max_used_priority = 0;
239 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
240 (uint8_t *) &max_used_priority);
241 if (retval != ERROR_OK)
242 return retval;
243
244 int thread_list_size = 0;
245 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
246 param->thread_count_width, (uint8_t *) &thread_list_size);
247
248 if (retval != ERROR_OK) {
249 LOG_ERROR("Could not read embKernel thread count from target");
250 return retval;
251 }
252
253 /* create space for new thread details */
254 rtos->thread_details = (struct thread_detail *) malloc(sizeof(struct thread_detail) * thread_list_size);
255 if (!rtos->thread_details) {
256 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
257 return ERROR_FAIL;
258 }
259
260 int threadIdx = 0;
261 /* Look for ready tasks */
262 for (int pri = 0; pri < max_used_priority; pri++) {
263 /* Get first item in queue */
264 int64_t iterable = 0;
265 retval = target_read_buffer(rtos->target,
266 rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
267 (uint8_t *) &iterable);
268 if (retval != ERROR_OK)
269 return retval;
270 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
271 /* Get info from this iterable item */
272 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
273 if (retval != ERROR_OK)
274 return retval;
275 /* Get next iterable item */
276 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
277 (uint8_t *) &iterable);
278 if (retval != ERROR_OK)
279 return retval;
280 }
281 }
282 /* Look for sleeping tasks */
283 int64_t iterable = 0;
284 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width,
285 (uint8_t *) &iterable);
286 if (retval != ERROR_OK)
287 return retval;
288 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
289 /*Get info from this iterable item */
290 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping");
291 if (retval != ERROR_OK)
292 return retval;
293 /*Get next iterable item */
294 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
295 (uint8_t *) &iterable);
296 if (retval != ERROR_OK)
297 return retval;
298 }
299
300 /* Look for suspended tasks */
301 iterable = 0;
302 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width,
303 (uint8_t *) &iterable);
304 if (retval != ERROR_OK)
305 return retval;
306 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
307 /* Get info from this iterable item */
308 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended");
309 if (retval != ERROR_OK)
310 return retval;
311 /*Get next iterable item */
312 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
313 (uint8_t *) &iterable);
314 if (retval != ERROR_OK)
315 return retval;
316 }
317
318 rtos->thread_count = 0;
319 rtos->thread_count = threadIdx;
320 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
321 return 0;
322 }
323
324 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
325 {
326 int retval;
327 const struct embKernel_params *param;
328 int64_t stack_ptr = 0;
329
330 *hex_reg_list = NULL;
331 if (rtos == NULL)
332 return -1;
333
334 if (thread_id == 0)
335 return -2;
336
337 if (rtos->rtos_specific_params == NULL)
338 return -1;
339
340 param = (const struct embKernel_params *) rtos->rtos_specific_params;
341
342 /* Read the stack pointer */
343 retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
344 (uint8_t *) &stack_ptr);
345 if (retval != ERROR_OK) {
346 LOG_ERROR("Error reading stack frame from embKernel thread");
347 return retval;
348 }
349
350 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
351 }
352
353 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
354 {
355 unsigned int i;
356 *symbol_list = (symbol_table_elem_t *) malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(embKernel_symbol_list));
357
358 for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
359 (*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
360
361 return 0;
362 }
363