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");
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)