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 we just invented thread 1 to represent the current execution, we
324 * need to make sure the RTOS object also claims it's the current thread
325 * so that threadx_get_thread_reg_list() doesn't attempt to read a
326 * thread control block at 0x00000001. */
327 rtos
->current_thread
= 1;
329 if (thread_list_size
== 0) {
330 rtos
->thread_count
= 1;
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");
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
];
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");
372 /* Read the thread name */
375 /* Check if thread has a valid name */
378 target_read_buffer(rtos
->target
,
380 THREADX_THREAD_NAME_STR_SIZE
,
381 (uint8_t *)&tmp_str
);
382 if (retval
!= ERROR_OK
) {
383 LOG_ERROR("Error reading thread name from ThreadX target");
386 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
- 1] = '\x00';
389 if (tmp_str
[0] == '\x00')
390 strcpy(tmp_str
, "No Name");
392 rtos
->thread_details
[tasks_found
].thread_name_str
=
393 malloc(strlen(tmp_str
)+1);
394 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
396 /* Read the thread status */
397 int64_t thread_status
= 0;
398 retval
= target_read_buffer(rtos
->target
,
399 thread_ptr
+ param
->thread_state_offset
,
401 (uint8_t *)&thread_status
);
402 if (retval
!= ERROR_OK
) {
403 LOG_ERROR("Error reading thread state from ThreadX target");
407 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
408 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
412 const char *state_desc
;
413 if (i
< THREADX_NUM_STATES
)
414 state_desc
= threadx_thread_states
[i
].desc
;
416 state_desc
= "Unknown state";
418 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(strlen(
420 sprintf(rtos
->thread_details
[tasks_found
].extra_info_str
, "State: %s", state_desc
);
422 rtos
->thread_details
[tasks_found
].exists
= true;
425 prev_thread_ptr
= thread_ptr
;
427 /* Get the location of the next thread structure. */
429 retval
= target_read_buffer(rtos
->target
,
430 prev_thread_ptr
+ param
->thread_next_offset
,
431 param
->pointer_width
,
432 (uint8_t *) &thread_ptr
);
433 if (retval
!= ERROR_OK
) {
434 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
439 rtos
->thread_count
= tasks_found
;
444 static int threadx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
445 struct rtos_reg
**reg_list
, int *num_regs
)
448 const struct threadx_params
*param
;
453 if (!is_thread_id_valid(rtos
, thread_id
))
456 if (!rtos
->rtos_specific_params
)
459 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
461 /* Read the stack pointer */
462 int64_t stack_ptr
= 0;
463 retval
= target_read_buffer(rtos
->target
,
464 thread_id
+ param
->thread_stack_offset
,
465 param
->pointer_width
,
466 (uint8_t *)&stack_ptr
);
467 if (retval
!= ERROR_OK
) {
468 LOG_ERROR("Error reading stack frame from ThreadX thread");
472 LOG_INFO("thread: 0x%" PRIx64
", stack_ptr=0x%" PRIx64
, (uint64_t)thread_id
, (uint64_t)stack_ptr
);
474 if (stack_ptr
== 0) {
475 LOG_ERROR("null stack pointer in thread");
479 const struct rtos_register_stacking
*stacking_info
=
480 get_stacking_info(rtos
, stack_ptr
);
482 if (!stacking_info
) {
483 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64
, (uint64_t)thread_id
);
487 return rtos_generic_stack_read(rtos
->target
, stacking_info
, stack_ptr
, reg_list
, num_regs
);
490 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
493 *symbol_list
= calloc(
494 ARRAY_SIZE(threadx_symbol_list
), sizeof(struct symbol_table_elem
));
496 for (i
= 0; i
< ARRAY_SIZE(threadx_symbol_list
); i
++)
497 (*symbol_list
)[i
].symbol_name
= threadx_symbol_list
[i
];
502 static bool threadx_detect_rtos(struct target
*target
)
504 if ((target
->rtos
->symbols
) &&
505 (target
->rtos
->symbols
[THREADX_VAL_TX_THREAD_CREATED_PTR
].address
!= 0)) {
506 /* looks like ThreadX */
514 static int threadx_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
519 static int threadx_get_thread_detail(struct rtos
*rtos
,
520 threadid_t thread_id
,
521 struct thread_detail
*detail
)
526 #define THREADX_THREAD_NAME_STR_SIZE (200)
527 char tmp_str
[THREADX_THREAD_NAME_STR_SIZE
];
529 const struct threadx_params
*param
;
537 if (!rtos
->rtos_specific_params
)
540 param
= (const struct threadx_params
*) rtos
->rtos_specific_params
;
542 if (!rtos
->symbols
) {
543 LOG_ERROR("No symbols for ThreadX");
547 detail
->threadid
= thread_id
;
549 int64_t name_ptr
= 0;
550 /* read the name pointer */
551 retval
= target_read_buffer(rtos
->target
,
552 thread_id
+ param
->thread_name_offset
,
553 param
->pointer_width
,
554 (uint8_t *)&name_ptr
);
555 if (retval
!= ERROR_OK
) {
556 LOG_ERROR("Could not read ThreadX thread name pointer from target");
560 /* Read the thread name */
561 retval
= target_read_buffer(rtos
->target
,
563 THREADX_THREAD_NAME_STR_SIZE
,
564 (uint8_t *)&tmp_str
);
565 if (retval
!= ERROR_OK
) {
566 LOG_ERROR("Error reading thread name from ThreadX target");
569 tmp_str
[THREADX_THREAD_NAME_STR_SIZE
-1] = '\x00';
571 if (tmp_str
[0] == '\x00')
572 strcpy(tmp_str
, "No Name");
574 detail
->thread_name_str
= malloc(strlen(tmp_str
)+1);
576 /* Read the thread status */
577 int64_t thread_status
= 0;
579 target_read_buffer(rtos
->target
,
580 thread_id
+ param
->thread_state_offset
,
582 (uint8_t *)&thread_status
);
583 if (retval
!= ERROR_OK
) {
584 LOG_ERROR("Error reading thread state from ThreadX target");
588 for (i
= 0; (i
< THREADX_NUM_STATES
) &&
589 (threadx_thread_states
[i
].value
!= thread_status
); i
++) {
594 if (i
< THREADX_NUM_STATES
)
595 state_desc
= threadx_thread_states
[i
].desc
;
597 state_desc
= "Unknown state";
599 detail
->extra_info_str
= malloc(strlen(state_desc
)+1);
601 detail
->exists
= true;
608 static int threadx_create(struct target
*target
)
610 for (unsigned int i
= 0; i
< ARRAY_SIZE(threadx_params_list
); i
++)
611 if (strcmp(threadx_params_list
[i
].target_name
, target
->type
->name
) == 0) {
612 target
->rtos
->rtos_specific_params
= (void *)&threadx_params_list
[i
];
613 target
->rtos
->current_thread
= 0;
614 target
->rtos
->thread_details
= NULL
;
618 LOG_ERROR("Could not find target in ThreadX compatibility list");