RTOS: ThreadX support on ARM926E-JS
[openocd.git] / src / rtos / ThreadX.c
blobc033125455f3995d3df63a1e579e4477dd97daea
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 ***************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
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_standard_stackings.h"
34 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr);
35 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr);
37 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id);
38 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id);
40 static int ThreadX_detect_rtos(struct target *target);
41 static int ThreadX_create(struct target *target);
42 static int ThreadX_update_threads(struct rtos *rtos);
43 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
44 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
48 struct ThreadX_thread_state {
49 int value;
50 const char *desc;
53 static const struct ThreadX_thread_state ThreadX_thread_states[] = {
54 { 0, "Ready" },
55 { 1, "Completed" },
56 { 2, "Terminated" },
57 { 3, "Suspended" },
58 { 4, "Sleeping" },
59 { 5, "Waiting - Queue" },
60 { 6, "Waiting - Semaphore" },
61 { 7, "Waiting - Event flag" },
62 { 8, "Waiting - Memory" },
63 { 9, "Waiting - Memory" },
64 { 10, "Waiting - I/O" },
65 { 11, "Waiting - Filesystem" },
66 { 12, "Waiting - Network" },
67 { 13, "Waiting - Mutex" },
70 #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
72 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
73 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
74 { -1, 32 }, /* r0 */
75 { -1, 32 }, /* r1 */
76 { -1, 32 }, /* r2 */
77 { -1, 32 }, /* r3 */
78 { 0x08, 32 }, /* r4 */
79 { 0x0C, 32 }, /* r5 */
80 { 0x10, 32 }, /* r6 */
81 { 0x14, 32 }, /* r7 */
82 { 0x18, 32 }, /* r8 */
83 { 0x1C, 32 }, /* r9 */
84 { 0x20, 32 }, /* r10 */
85 { 0x24, 32 }, /* r11 */
86 { -1, 32 }, /* r12 */
87 { -2, 32 }, /* sp (r13) */
88 { 0x28, 32 }, /* lr (r14) */
89 { -1, 32 }, /* pc (r15) */
90 /*{ -1, 32 },*/ /* lr (r14) */
91 /*{ 0x28, 32 },*/ /* pc (r15) */
92 { 0x04, 32 }, /* xPSR */
94 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
95 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = {
96 { 0x08, 32 }, /* r0 */
97 { 0x0C, 32 }, /* r1 */
98 { 0x10, 32 }, /* r2 */
99 { 0x14, 32 }, /* r3 */
100 { 0x18, 32 }, /* r4 */
101 { 0x1C, 32 }, /* r5 */
102 { 0x20, 32 }, /* r6 */
103 { 0x24, 32 }, /* r7 */
104 { 0x28, 32 }, /* r8 */
105 { 0x2C, 32 }, /* r9 */
106 { 0x30, 32 }, /* r10 */
107 { 0x34, 32 }, /* r11 */
108 { 0x38, 32 }, /* r12 */
109 { -2, 32 }, /* sp (r13) */
110 { 0x3C, 32 }, /* lr (r14) */
111 { 0x40, 32 }, /* pc (r15) */
112 { 0x04, 32 }, /* xPSR */
115 const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
117 ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */
118 -1, /* stack_growth_direction */
119 17, /* num_output_registers */
120 0, /* stack_alignment */
121 rtos_threadx_arm926ejs_stack_offsets_solicited /* register_offsets */
124 ARM926EJS_REGISTERS_SIZE_INTERRUPT, /* stack_registers_size */
125 -1, /* stack_growth_direction */
126 17, /* num_output_registers */
127 0, /* stack_alignment */
128 rtos_threadx_arm926ejs_stack_offsets_interrupt /* register_offsets */
132 struct ThreadX_params {
133 const char *target_name;
134 unsigned char pointer_width;
135 unsigned char thread_stack_offset;
136 unsigned char thread_name_offset;
137 unsigned char thread_state_offset;
138 unsigned char thread_next_offset;
139 const struct rtos_register_stacking *stacking_info;
140 size_t stacking_info_nb;
141 const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr);
142 int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id);
145 static const struct ThreadX_params ThreadX_params_list[] = {
147 "cortex_m", /* target_name */
148 4, /* pointer_width; */
149 8, /* thread_stack_offset; */
150 40, /* thread_name_offset; */
151 48, /* thread_state_offset; */
152 136, /* thread_next_offset */
153 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
154 1, /* stacking_info_nb */
155 NULL, /* fn_get_stacking_info */
156 NULL, /* fn_is_thread_id_valid */
159 "cortex_r4", /* target_name */
160 4, /* pointer_width; */
161 8, /* thread_stack_offset; */
162 40, /* thread_name_offset; */
163 48, /* thread_state_offset; */
164 136, /* thread_next_offset */
165 &rtos_standard_Cortex_R4_stacking, /* stacking_info */
166 1, /* stacking_info_nb */
167 NULL, /* fn_get_stacking_info */
168 NULL, /* fn_is_thread_id_valid */
171 "arm926ejs", /* target_name */
172 4, /* pointer_width; */
173 8, /* thread_stack_offset; */
174 40, /* thread_name_offset; */
175 48, /* thread_state_offset; */
176 136, /* thread_next_offset */
177 rtos_threadx_arm926ejs_stacking, /* stacking_info */
178 2, /* stacking_info_nb */
179 get_stacking_info_arm926ejs, /* fn_get_stacking_info */
180 is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */
184 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
186 enum ThreadX_symbol_values {
187 ThreadX_VAL_tx_thread_current_ptr = 0,
188 ThreadX_VAL_tx_thread_created_ptr = 1,
189 ThreadX_VAL_tx_thread_created_count = 2,
192 static const char * const ThreadX_symbol_list[] = {
193 "_tx_thread_current_ptr",
194 "_tx_thread_created_ptr",
195 "_tx_thread_created_count",
196 NULL
199 const struct rtos_type ThreadX_rtos = {
200 .name = "ThreadX",
202 .detect_rtos = ThreadX_detect_rtos,
203 .create = ThreadX_create,
204 .update_threads = ThreadX_update_threads,
205 .get_thread_reg_list = ThreadX_get_thread_reg_list,
206 .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup,
209 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
211 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
213 if (param->fn_get_stacking_info != NULL)
214 return param->fn_get_stacking_info(rtos, stack_ptr);
216 return param->stacking_info + 0;
219 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
221 const struct ThreadX_params *param;
223 if (rtos->rtos_specific_params == NULL)
224 return 0; /* invalid */
226 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
228 if (param->fn_is_thread_id_valid != NULL)
229 return param->fn_is_thread_id_valid(rtos, thread_id);
231 return (thread_id != 0);
234 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
236 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
237 int retval;
238 uint32_t flag;
240 retval = target_read_buffer(rtos->target,
241 stack_ptr,
242 sizeof(flag),
243 (uint8_t *)&flag);
244 if (retval != ERROR_OK) {
245 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
246 return NULL;
249 if (flag == 0) {
250 LOG_DEBUG(" solicited stack");
251 return param->stacking_info + 0;
252 } else {
253 LOG_DEBUG(" interrupt stack: %u", flag);
254 return param->stacking_info + 1;
258 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
260 return (thread_id != 0 && thread_id != 1);
263 static int ThreadX_update_threads(struct rtos *rtos)
265 int retval;
266 int tasks_found = 0;
267 int thread_list_size = 0;
268 const struct ThreadX_params *param;
270 if (rtos == NULL)
271 return -1;
273 if (rtos->rtos_specific_params == NULL)
274 return -3;
276 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
278 if (rtos->symbols == NULL) {
279 LOG_ERROR("No symbols for ThreadX");
280 return -4;
283 if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) {
284 LOG_ERROR("Don't have the number of threads in ThreadX");
285 return -2;
288 /* read the number of threads */
289 retval = target_read_buffer(rtos->target,
290 rtos->symbols[ThreadX_VAL_tx_thread_created_count].address,
292 (uint8_t *)&thread_list_size);
294 if (retval != ERROR_OK) {
295 LOG_ERROR("Could not read ThreadX thread count from target");
296 return retval;
299 /* wipe out previous thread details if any */
300 rtos_free_threadlist(rtos);
302 /* read the current thread id */
303 retval = target_read_buffer(rtos->target,
304 rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address,
306 (uint8_t *)&rtos->current_thread);
308 if (retval != ERROR_OK) {
309 LOG_ERROR("Could not read ThreadX current thread from target");
310 return retval;
313 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
314 /* Either : No RTOS threads - there is always at least the current execution though */
315 /* OR : No current thread - all threads suspended - show the current execution
316 * of idling */
317 char tmp_str[] = "Current Execution";
318 thread_list_size++;
319 tasks_found++;
320 rtos->thread_details = malloc(
321 sizeof(struct thread_detail) * thread_list_size);
322 rtos->thread_details->threadid = 1;
323 rtos->thread_details->exists = true;
324 rtos->thread_details->display_str = NULL;
325 rtos->thread_details->extra_info_str = NULL;
326 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
327 strcpy(rtos->thread_details->thread_name_str, tmp_str);
329 if (thread_list_size == 0) {
330 rtos->thread_count = 1;
331 return ERROR_OK;
333 } else {
334 /* create space for new thread details */
335 rtos->thread_details = malloc(
336 sizeof(struct thread_detail) * thread_list_size);
339 /* Read the pointer to the first thread */
340 int64_t thread_ptr = 0;
341 retval = target_read_buffer(rtos->target,
342 rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address,
343 param->pointer_width,
344 (uint8_t *)&thread_ptr);
345 if (retval != ERROR_OK) {
346 LOG_ERROR("Could not read ThreadX thread location from target");
347 return retval;
350 /* loop over all threads */
351 int64_t prev_thread_ptr = 0;
352 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
354 #define THREADX_THREAD_NAME_STR_SIZE (200)
355 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
356 unsigned int i = 0;
357 int64_t name_ptr = 0;
359 /* Save the thread pointer */
360 rtos->thread_details[tasks_found].threadid = thread_ptr;
362 /* read the name pointer */
363 retval = target_read_buffer(rtos->target,
364 thread_ptr + param->thread_name_offset,
365 param->pointer_width,
366 (uint8_t *)&name_ptr);
367 if (retval != ERROR_OK) {
368 LOG_ERROR("Could not read ThreadX thread name pointer from target");
369 return retval;
372 /* Read the thread name */
373 retval =
374 target_read_buffer(rtos->target,
375 name_ptr,
376 THREADX_THREAD_NAME_STR_SIZE,
377 (uint8_t *)&tmp_str);
378 if (retval != ERROR_OK) {
379 LOG_ERROR("Error reading thread name from ThreadX target");
380 return retval;
382 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
384 if (tmp_str[0] == '\x00')
385 strcpy(tmp_str, "No Name");
387 rtos->thread_details[tasks_found].thread_name_str =
388 malloc(strlen(tmp_str)+1);
389 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
391 /* Read the thread status */
392 int64_t thread_status = 0;
393 retval = target_read_buffer(rtos->target,
394 thread_ptr + param->thread_state_offset,
396 (uint8_t *)&thread_status);
397 if (retval != ERROR_OK) {
398 LOG_ERROR("Error reading thread state from ThreadX target");
399 return retval;
402 for (i = 0; (i < THREADX_NUM_STATES) &&
403 (ThreadX_thread_states[i].value != thread_status); i++) {
404 /* empty */
407 const char *state_desc;
408 if (i < THREADX_NUM_STATES)
409 state_desc = ThreadX_thread_states[i].desc;
410 else
411 state_desc = "Unknown state";
413 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
414 state_desc)+1);
415 strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
417 rtos->thread_details[tasks_found].exists = true;
419 rtos->thread_details[tasks_found].display_str = NULL;
421 tasks_found++;
422 prev_thread_ptr = thread_ptr;
424 /* Get the location of the next thread structure. */
425 thread_ptr = 0;
426 retval = target_read_buffer(rtos->target,
427 prev_thread_ptr + param->thread_next_offset,
428 param->pointer_width,
429 (uint8_t *) &thread_ptr);
430 if (retval != ERROR_OK) {
431 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
432 return retval;
436 rtos->thread_count = tasks_found;
438 return 0;
441 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
443 int retval;
444 const struct ThreadX_params *param;
446 *hex_reg_list = NULL;
448 if (rtos == NULL)
449 return -1;
451 if (!is_thread_id_valid(rtos, thread_id))
452 return -2;
454 if (rtos->rtos_specific_params == NULL)
455 return -3;
457 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
459 /* Read the stack pointer */
460 int64_t stack_ptr = 0;
461 retval = target_read_buffer(rtos->target,
462 thread_id + param->thread_stack_offset,
463 param->pointer_width,
464 (uint8_t *)&stack_ptr);
465 if (retval != ERROR_OK) {
466 LOG_ERROR("Error reading stack frame from ThreadX thread");
467 return retval;
470 LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
472 if (stack_ptr == 0) {
473 LOG_ERROR("null stack pointer in thread");
474 return -5;
477 const struct rtos_register_stacking *stacking_info =
478 get_stacking_info(rtos, stack_ptr);
480 if (stacking_info == NULL) {
481 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
482 return -6;
485 return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, hex_reg_list);
488 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
490 unsigned int i;
491 *symbol_list = calloc(
492 ARRAY_SIZE(ThreadX_symbol_list), sizeof(symbol_table_elem_t));
494 for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++)
495 (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
497 return 0;
500 static int ThreadX_detect_rtos(struct target *target)
502 if ((target->rtos->symbols != NULL) &&
503 (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) {
504 /* looks like ThreadX */
505 return 1;
507 return 0;
510 #if 0
512 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id)
514 return 0;
517 static int ThreadX_get_thread_detail(struct rtos *rtos,
518 threadid_t thread_id,
519 struct thread_detail *detail)
521 unsigned int i = 0;
522 int retval;
524 #define THREADX_THREAD_NAME_STR_SIZE (200)
525 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
527 const struct ThreadX_params *param;
529 if (rtos == NULL)
530 return -1;
532 if (thread_id == 0)
533 return -2;
535 if (rtos->rtos_specific_params == NULL)
536 return -3;
538 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
540 if (rtos->symbols == NULL) {
541 LOG_ERROR("No symbols for ThreadX");
542 return -3;
545 detail->threadid = thread_id;
547 int64_t name_ptr = 0;
548 /* read the name pointer */
549 retval = target_read_buffer(rtos->target,
550 thread_id + param->thread_name_offset,
551 param->pointer_width,
552 (uint8_t *)&name_ptr);
553 if (retval != ERROR_OK) {
554 LOG_ERROR("Could not read ThreadX thread name pointer from target");
555 return retval;
558 /* Read the thread name */
559 retval = target_read_buffer(rtos->target,
560 name_ptr,
561 THREADX_THREAD_NAME_STR_SIZE,
562 (uint8_t *)&tmp_str);
563 if (retval != ERROR_OK) {
564 LOG_ERROR("Error reading thread name from ThreadX target");
565 return retval;
567 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
569 if (tmp_str[0] == '\x00')
570 strcpy(tmp_str, "No Name");
572 detail->thread_name_str = malloc(strlen(tmp_str)+1);
574 /* Read the thread status */
575 int64_t thread_status = 0;
576 retval =
577 target_read_buffer(rtos->target,
578 thread_id + param->thread_state_offset,
580 (uint8_t *)&thread_status);
581 if (retval != ERROR_OK) {
582 LOG_ERROR("Error reading thread state from ThreadX target");
583 return retval;
586 for (i = 0; (i < THREADX_NUM_STATES) &&
587 (ThreadX_thread_states[i].value != thread_status); i++) {
588 /* empty */
591 char *state_desc;
592 if (i < THREADX_NUM_STATES)
593 state_desc = ThreadX_thread_states[i].desc;
594 else
595 state_desc = "Unknown state";
597 detail->extra_info_str = malloc(strlen(state_desc)+1);
599 detail->exists = true;
601 detail->display_str = NULL;
603 return 0;
606 #endif
608 static int ThreadX_create(struct target *target)
610 int i = 0;
611 while ((i < THREADX_NUM_PARAMS) &&
612 (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) {
613 i++;
615 if (i >= THREADX_NUM_PARAMS) {
616 LOG_ERROR("Could not find target in ThreadX compatibility list");
617 return -1;
620 target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i];
621 target->rtos->current_thread = 0;
622 target->rtos->thread_details = NULL;
623 return 0;