1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2011 by Broadcom Corporation *
5 * Evan Hunter - ehunter@broadcom.com *
6 ***************************************************************************/
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos_standard_stackings.h"
21 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
);
22 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
);
24 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
);
25 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
);
27 static bool threadx_detect_rtos(struct target
*target
);
28 static int threadx_create(struct target
*target
);
29 static int threadx_update_threads(struct rtos
*rtos
);
30 static int threadx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, struct rtos_reg
**reg_list
, int *num_regs
);
31 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
35 struct threadx_thread_state
{
40 static const struct threadx_thread_state threadx_thread_states
[] = {
46 { 5, "Waiting - Queue" },
47 { 6, "Waiting - Semaphore" },
48 { 7, "Waiting - Event flag" },
49 { 8, "Waiting - Memory" },
50 { 9, "Waiting - Memory" },
51 { 10, "Waiting - I/O" },
52 { 11, "Waiting - Filesystem" },
53 { 12, "Waiting - Network" },
54 { 13, "Waiting - Mutex" },
57 #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states)
59 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
60 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited
[] = {
61 { 0, -1, 32 }, /* r0 */
62 { 1, -1, 32 }, /* r1 */
63 { 2, -1, 32 }, /* r2 */
64 { 3, -1, 32 }, /* r3 */
65 { 4, 0x08, 32 }, /* r4 */
66 { 5, 0x0C, 32 }, /* r5 */
67 { 6, 0x10, 32 }, /* r6 */
68 { 7, 0x14, 32 }, /* r7 */
69 { 8, 0x18, 32 }, /* r8 */
70 { 9, 0x1C, 32 }, /* r9 */
71 { 10, 0x20, 32 }, /* r10 */
72 { 11, 0x24, 32 }, /* r11 */
73 { 12, -1, 32 }, /* r12 */
74 { 13, -2, 32 }, /* sp (r13) */
75 { 14, 0x28, 32 }, /* lr (r14) */
76 { 15, -1, 32 }, /* pc (r15) */
77 /*{ 16, -1, 32 },*/ /* lr (r14) */
78 /*{ 17, 0x28, 32 },*/ /* pc (r15) */
79 { 16, 0x04, 32 }, /* xPSR */
81 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
82 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt
[] = {
83 { 0, 0x08, 32 }, /* r0 */
84 { 1, 0x0C, 32 }, /* r1 */
85 { 2, 0x10, 32 }, /* r2 */
86 { 3, 0x14, 32 }, /* r3 */
87 { 4, 0x18, 32 }, /* r4 */
88 { 5, 0x1C, 32 }, /* r5 */
89 { 6, 0x20, 32 }, /* r6 */
90 { 7, 0x24, 32 }, /* r7 */
91 { 8, 0x28, 32 }, /* r8 */
92 { 9, 0x2C, 32 }, /* r9 */
93 { 10, 0x30, 32 }, /* r10 */
94 { 11, 0x34, 32 }, /* r11 */
95 { 12, 0x38, 32 }, /* r12 */
96 { 13, -2, 32 }, /* sp (r13) */
97 { 14, 0x3C, 32 }, /* lr (r14) */
98 { 15, 0x40, 32 }, /* pc (r15) */
99 { 16, 0x04, 32 }, /* xPSR */
102 static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking
[] = {
104 .stack_registers_size
= ARM926EJS_REGISTERS_SIZE_SOLICITED
,
105 .stack_growth_direction
= -1,
106 .num_output_registers
= 17,
107 .register_offsets
= rtos_threadx_arm926ejs_stack_offsets_solicited
110 .stack_registers_size
= ARM926EJS_REGISTERS_SIZE_INTERRUPT
,
111 .stack_growth_direction
= -1,
112 .num_output_registers
= 17,
113 .register_offsets
= rtos_threadx_arm926ejs_stack_offsets_interrupt
117 struct threadx_params
{
118 const char *target_name
;
119 unsigned char pointer_width
;
120 unsigned char thread_stack_offset
;
121 unsigned char thread_name_offset
;
122 unsigned char thread_state_offset
;
123 unsigned char thread_next_offset
;
124 const struct rtos_register_stacking
*stacking_info
;
125 size_t stacking_info_nb
;
126 const struct rtos_register_stacking
* (*fn_get_stacking_info
)(const struct rtos
*rtos
, int64_t stack_ptr
);
127 int (*fn_is_thread_id_valid
)(const struct rtos
*rtos
, int64_t thread_id
);
130 static const struct threadx_params threadx_params_list
[] = {
132 "cortex_m", /* target_name */
133 4, /* pointer_width; */
134 8, /* thread_stack_offset; */
135 40, /* thread_name_offset; */
136 48, /* thread_state_offset; */
137 136, /* thread_next_offset */
138 &rtos_standard_cortex_m3_stacking
, /* stacking_info */
139 1, /* stacking_info_nb */
140 NULL
, /* fn_get_stacking_info */
141 NULL
, /* fn_is_thread_id_valid */
144 "cortex_r4", /* target_name */
145 4, /* pointer_width; */
146 8, /* thread_stack_offset; */
147 40, /* thread_name_offset; */
148 48, /* thread_state_offset; */
149 136, /* thread_next_offset */
150 &rtos_standard_cortex_r4_stacking
, /* stacking_info */
151 1, /* stacking_info_nb */
152 NULL
, /* fn_get_stacking_info */
153 NULL
, /* fn_is_thread_id_valid */
156 "arm926ejs", /* target_name */
157 4, /* pointer_width; */
158 8, /* thread_stack_offset; */
159 40, /* thread_name_offset; */
160 48, /* thread_state_offset; */
161 136, /* thread_next_offset */
162 rtos_threadx_arm926ejs_stacking
, /* stacking_info */
163 2, /* stacking_info_nb */
164 get_stacking_info_arm926ejs
, /* fn_get_stacking_info */
165 is_thread_id_valid_arm926ejs
, /* fn_is_thread_id_valid */
168 "hla_target", /* target_name */
169 4, /* pointer_width; */
170 8, /* thread_stack_offset; */
171 40, /* thread_name_offset; */
172 48, /* thread_state_offset; */
173 136, /* thread_next_offset */
174 &rtos_standard_cortex_m3_stacking
, /* stacking_info */
175 1, /* stacking_info_nb */
176 NULL
, /* fn_get_stacking_info */
177 NULL
, /* fn_is_thread_id_valid */
181 enum threadx_symbol_values
{
182 THREADX_VAL_TX_THREAD_CURRENT_PTR
= 0,
183 THREADX_VAL_TX_THREAD_CREATED_PTR
= 1,
184 THREADX_VAL_TX_THREAD_CREATED_COUNT
= 2,
187 static const char * const threadx_symbol_list
[] = {
188 "_tx_thread_current_ptr",
189 "_tx_thread_created_ptr",
190 "_tx_thread_created_count",
194 const struct rtos_type threadx_rtos
= {
197 .detect_rtos
= threadx_detect_rtos
,
198 .create
= threadx_create
,
199 .update_threads
= threadx_update_threads
,
200 .get_thread_reg_list
= threadx_get_thread_reg_list
,
201 .get_symbol_list_to_lookup
= threadx_get_symbol_list_to_lookup
,
204 static const struct rtos_register_stacking
*get_stacking_info(const struct rtos
*rtos
, int64_t stack_ptr
)
206 const struct threadx_params
*param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
208 if (param
->fn_get_stacking_info
)
209 return param
->fn_get_stacking_info(rtos
, stack_ptr
);
211 return param
->stacking_info
+ 0;
214 static int is_thread_id_valid(const struct rtos
*rtos
, int64_t thread_id
)
216 const struct threadx_params
*param
;
218 if (!rtos
->rtos_specific_params
)
219 return 0; /* invalid */
221 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
223 if (param
->fn_is_thread_id_valid
)
224 return param
->fn_is_thread_id_valid(rtos
, thread_id
);
226 return (thread_id
!= 0);
229 static const struct rtos_register_stacking
*get_stacking_info_arm926ejs(const struct rtos
*rtos
, int64_t stack_ptr
)
231 const struct threadx_params
*param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
235 retval
= target_read_buffer(rtos
->target
,
239 if (retval
!= ERROR_OK
) {
240 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64
, stack_ptr
);
245 LOG_DEBUG(" solicited stack");
246 return param
->stacking_info
+ 0;
248 LOG_DEBUG(" interrupt stack: %" PRIu32
, flag
);
249 return param
->stacking_info
+ 1;
253 static int is_thread_id_valid_arm926ejs(const struct rtos
*rtos
, int64_t thread_id
)
255 return (thread_id
!= 0 && thread_id
!= 1);
258 static int threadx_update_threads(struct rtos
*rtos
)
262 int thread_list_size
= 0;
263 const struct threadx_params
*param
;
268 if (!rtos
->rtos_specific_params
)
271 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
273 if (!rtos
->symbols
) {
274 LOG_ERROR("No symbols for ThreadX");
278 if (rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_COUNT
].address
== 0) {
279 LOG_ERROR("Don't have the number of threads in ThreadX");
283 /* read the number of threads */
284 retval
= target_read_buffer(rtos
->target
,
285 rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_COUNT
].address
,
287 (uint8_t *)&thread_list_size
);
289 if (retval
!= ERROR_OK
) {
290 LOG_ERROR("Could not read ThreadX thread count from target");
294 /* wipe out previous thread details if any */
295 rtos_free_threadlist(rtos
);
297 /* read the current thread id */
298 retval
= target_read_buffer(rtos
->target
,
299 rtos
->symbols
[THREADX_VAL_TX_THREAD_CURRENT_PTR
].address
,
301 (uint8_t *)&rtos
->current_thread
);
303 if (retval
!= ERROR_OK
) {
304 LOG_ERROR("Could not read ThreadX current thread from target");
308 if ((thread_list_size
== 0) || (rtos
->current_thread
== 0)) {
309 /* Either : No RTOS threads - there is always at least the current execution though */
310 /* OR : No current thread - all threads suspended - show the current execution
312 char tmp_str
[] = "Current Execution";
315 rtos
->thread_details
= malloc(
316 sizeof(struct thread_detail
) * thread_list_size
);
317 rtos
->thread_details
->threadid
= 1;
318 rtos
->thread_details
->exists
= true;
319 rtos
->thread_details
->extra_info_str
= NULL
;
320 rtos
->thread_details
->thread_name_str
= malloc(sizeof(tmp_str
));
321 strcpy(rtos
->thread_details
->thread_name_str
, tmp_str
);
323 if (thread_list_size
== 0) {
324 rtos
->thread_count
= 1;
328 /* create space for new thread details */
329 rtos
->thread_details
= malloc(
330 sizeof(struct thread_detail
) * thread_list_size
);
333 /* Read the pointer to the first thread */
334 int64_t thread_ptr
= 0;
335 retval
= target_read_buffer(rtos
->target
,
336 rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_PTR
].address
,
337 param
->pointer_width
,
338 (uint8_t *)&thread_ptr
);
339 if (retval
!= ERROR_OK
) {
340 LOG_ERROR("Could not read ThreadX thread location from target");
344 /* loop over all threads */
345 int64_t prev_thread_ptr
= 0;
346 while ((thread_ptr
!= prev_thread_ptr
) && (tasks_found
< thread_list_size
)) {
348 #define THREADX_THREAD_NAME_STR_SIZE (200)
349 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
351 int64_t name_ptr
= 0;
353 /* Save the thread pointer */
354 rtos
->thread_details
[tasks_found
].threadid
= thread_ptr
;
356 /* read the name pointer */
357 retval
= target_read_buffer(rtos
->target
,
358 thread_ptr
+ param
->thread_name_offset
,
359 param
->pointer_width
,
360 (uint8_t *)&name_ptr
);
361 if (retval
!= ERROR_OK
) {
362 LOG_ERROR("Could not read ThreadX thread name pointer from target");
366 /* Read the thread name */
368 target_read_buffer(rtos
->target
,
370 THREADX_THREAD_NAME_STR_SIZE
,
371 (uint8_t *)&tmp_str
);
372 if (retval
!= ERROR_OK
) {
373 LOG_ERROR("Error reading thread name from ThreadX target");
376 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
378 if (tmp_str
[0] == '\x00')
379 strcpy(tmp_str
, "No Name");
381 rtos
->thread_details
[tasks_found
].thread_name_str
=
382 malloc(strlen(tmp_str
)+1);
383 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
385 /* Read the thread status */
386 int64_t thread_status
= 0;
387 retval
= target_read_buffer(rtos
->target
,
388 thread_ptr
+ param
->thread_state_offset
,
390 (uint8_t *)&thread_status
);
391 if (retval
!= ERROR_OK
) {
392 LOG_ERROR("Error reading thread state from ThreadX target");
396 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
397 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
401 const char *state_desc
;
402 if (i
< THREADX_NUM_STATES
)
403 state_desc
= threadx_thread_states
[i
].desc
;
405 state_desc
= "Unknown state";
407 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
409 sprintf(rtos
->thread_details
[tasks_found
].extra_info_str
, "State: %s", state_desc
);
411 rtos
->thread_details
[tasks_found
].exists
= true;
414 prev_thread_ptr
= thread_ptr
;
416 /* Get the location of the next thread structure. */
418 retval
= target_read_buffer(rtos
->target
,
419 prev_thread_ptr
+ param
->thread_next_offset
,
420 param
->pointer_width
,
421 (uint8_t *) &thread_ptr
);
422 if (retval
!= ERROR_OK
) {
423 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
428 rtos
->thread_count
= tasks_found
;
433 static int threadx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
434 struct rtos_reg
**reg_list
, int *num_regs
)
437 const struct threadx_params
*param
;
442 if (!is_thread_id_valid(rtos
, thread_id
))
445 if (!rtos
->rtos_specific_params
)
448 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
450 /* Read the stack pointer */
451 int64_t stack_ptr
= 0;
452 retval
= target_read_buffer(rtos
->target
,
453 thread_id
+ param
->thread_stack_offset
,
454 param
->pointer_width
,
455 (uint8_t *)&stack_ptr
);
456 if (retval
!= ERROR_OK
) {
457 LOG_ERROR("Error reading stack frame from ThreadX thread");
461 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
463 if (stack_ptr
== 0) {
464 LOG_ERROR("null stack pointer in thread");
468 const struct rtos_register_stacking
*stacking_info
=
469 get_stacking_info(rtos
, stack_ptr
);
471 if (!stacking_info
) {
472 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
476 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, reg_list
, num_regs
);
479 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
482 *symbol_list
= calloc(
483 ARRAY_SIZE(threadx_symbol_list
), sizeof(struct symbol_table_elem
));
485 for (i
= 0; i
< ARRAY_SIZE(threadx_symbol_list
); i
++)
486 (*symbol_list
)[i
].symbol_name
= threadx_symbol_list
[i
];
491 static bool threadx_detect_rtos(struct target
*target
)
493 if ((target
->rtos
->symbols
) &&
494 (target
->rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_PTR
].address
!= 0)) {
495 /* looks like ThreadX */
503 static int threadx_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
508 static int threadx_get_thread_detail(struct rtos
*rtos
,
509 threadid_t thread_id
,
510 struct thread_detail
*detail
)
515 #define THREADX_THREAD_NAME_STR_SIZE (200)
516 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
518 const struct threadx_params
*param
;
526 if (!rtos
->rtos_specific_params
)
529 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
531 if (!rtos
->symbols
) {
532 LOG_ERROR("No symbols for ThreadX");
536 detail
->threadid
= thread_id
;
538 int64_t name_ptr
= 0;
539 /* read the name pointer */
540 retval
= target_read_buffer(rtos
->target
,
541 thread_id
+ param
->thread_name_offset
,
542 param
->pointer_width
,
543 (uint8_t *)&name_ptr
);
544 if (retval
!= ERROR_OK
) {
545 LOG_ERROR("Could not read ThreadX thread name pointer from target");
549 /* Read the thread name */
550 retval
= target_read_buffer(rtos
->target
,
552 THREADX_THREAD_NAME_STR_SIZE
,
553 (uint8_t *)&tmp_str
);
554 if (retval
!= ERROR_OK
) {
555 LOG_ERROR("Error reading thread name from ThreadX target");
558 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
560 if (tmp_str
[0] == '\x00')
561 strcpy(tmp_str
, "No Name");
563 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
565 /* Read the thread status */
566 int64_t thread_status
= 0;
568 target_read_buffer(rtos
->target
,
569 thread_id
+ param
->thread_state_offset
,
571 (uint8_t *)&thread_status
);
572 if (retval
!= ERROR_OK
) {
573 LOG_ERROR("Error reading thread state from ThreadX target");
577 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
578 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
583 if (i
< THREADX_NUM_STATES
)
584 state_desc
= threadx_thread_states
[i
].desc
;
586 state_desc
= "Unknown state";
588 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
590 detail
->exists
= true;
597 static int threadx_create(struct target
*target
)
599 for (unsigned int i
= 0; i
< ARRAY_SIZE(threadx_params_list
); i
++)
600 if (strcmp(threadx_params_list
[i
].target_name
, target
->type
->name
) == 0) {
601 target
->rtos
->rtos_specific_params
= (void *)&threadx_params_list
[i
];
602 target
->rtos
->current_thread
= 0;
603 target
->rtos
->thread_details
= NULL
;
607 LOG_ERROR("Could not find target in ThreadX compatibility list");