5f90eb6445d40d2a4a1d5915234d2803f9c21f88
[openocd.git] / src / rtos / ThreadX.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2011 by Broadcom Corporation *
5 * Evan Hunter - ehunter@broadcom.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos_standard_stackings.h"
20
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);
23
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);
26
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[]);
32
33
34
35 struct threadx_thread_state {
36 int value;
37 const char *desc;
38 };
39
40 static const struct threadx_thread_state threadx_thread_states[] = {
41 { 0, "Ready" },
42 { 1, "Completed" },
43 { 2, "Terminated" },
44 { 3, "Suspended" },
45 { 4, "Sleeping" },
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" },
55 };
56
57 #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states)
58
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 */
80 };
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 */
100 };
101
102 static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
103 {
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
108 },
109 {
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
114 },
115 };
116
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);
128 };
129
130 static const struct threadx_params threadx_params_list[] = {
131 {
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 */
142 },
143 {
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 */
154 },
155 {
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 */
166 },
167 {
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 */
178 },
179 };
180
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,
185 };
186
187 static const char * const threadx_symbol_list[] = {
188 "_tx_thread_current_ptr",
189 "_tx_thread_created_ptr",
190 "_tx_thread_created_count",
191 NULL
192 };
193
194 const struct rtos_type threadx_rtos = {
195 .name = "ThreadX",
196
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,
202 };
203
204 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
205 {
206 const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
207
208 if (param->fn_get_stacking_info)
209 return param->fn_get_stacking_info(rtos, stack_ptr);
210
211 return param->stacking_info + 0;
212 }
213
214 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
215 {
216 const struct threadx_params *param;
217
218 if (!rtos->rtos_specific_params)
219 return 0; /* invalid */
220
221 param = (const struct threadx_params *) rtos->rtos_specific_params;
222
223 if (param->fn_is_thread_id_valid)
224 return param->fn_is_thread_id_valid(rtos, thread_id);
225
226 return (thread_id != 0);
227 }
228
229 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
230 {
231 const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
232 int retval;
233 uint32_t flag;
234
235 retval = target_read_buffer(rtos->target,
236 stack_ptr,
237 sizeof(flag),
238 (uint8_t *)&flag);
239 if (retval != ERROR_OK) {
240 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
241 return NULL;
242 }
243
244 if (flag == 0) {
245 LOG_DEBUG(" solicited stack");
246 return param->stacking_info + 0;
247 } else {
248 LOG_DEBUG(" interrupt stack: %" PRIu32, flag);
249 return param->stacking_info + 1;
250 }
251 }
252
253 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
254 {
255 return (thread_id != 0 && thread_id != 1);
256 }
257
258 static int threadx_update_threads(struct rtos *rtos)
259 {
260 int retval;
261 int tasks_found = 0;
262 int thread_list_size = 0;
263 const struct threadx_params *param;
264
265 if (!rtos)
266 return -1;
267
268 if (!rtos->rtos_specific_params)
269 return -3;
270
271 param = (const struct threadx_params *) rtos->rtos_specific_params;
272
273 if (!rtos->symbols) {
274 LOG_ERROR("No symbols for ThreadX");
275 return -4;
276 }
277
278 if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) {
279 LOG_ERROR("Don't have the number of threads in ThreadX");
280 return -2;
281 }
282
283 /* read the number of threads */
284 retval = target_read_buffer(rtos->target,
285 rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address,
286 4,
287 (uint8_t *)&thread_list_size);
288
289 if (retval != ERROR_OK) {
290 LOG_ERROR("Could not read ThreadX thread count from target");
291 return retval;
292 }
293
294 /* wipe out previous thread details if any */
295 rtos_free_threadlist(rtos);
296
297 /* read the current thread id */
298 retval = target_read_buffer(rtos->target,
299 rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address,
300 4,
301 (uint8_t *)&rtos->current_thread);
302
303 if (retval != ERROR_OK) {
304 LOG_ERROR("Could not read ThreadX current thread from target");
305 return retval;
306 }
307
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
311 * of idling */
312 char tmp_str[] = "Current Execution";
313 thread_list_size++;
314 tasks_found++;
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);
322
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;
328
329 if (thread_list_size == 0) {
330 rtos->thread_count = 1;
331 return ERROR_OK;
332 }
333 } else {
334 /* create space for new thread details */
335 rtos->thread_details = malloc(
336 sizeof(struct thread_detail) * thread_list_size);
337 }
338
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;
348 }
349
350 /* loop over all threads */
351 int64_t prev_thread_ptr = 0;
352 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
353
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;
358
359 /* Save the thread pointer */
360 rtos->thread_details[tasks_found].threadid = thread_ptr;
361
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;
370 }
371
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;
381 }
382 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
383
384 if (tmp_str[0] == '\x00')
385 strcpy(tmp_str, "No Name");
386
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);
390
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,
395 4,
396 (uint8_t *)&thread_status);
397 if (retval != ERROR_OK) {
398 LOG_ERROR("Error reading thread state from ThreadX target");
399 return retval;
400 }
401
402 for (i = 0; (i < THREADX_NUM_STATES) &&
403 (threadx_thread_states[i].value != thread_status); i++) {
404 /* empty */
405 }
406
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";
412
413 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
414 state_desc)+8);
415 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
416
417 rtos->thread_details[tasks_found].exists = true;
418
419 tasks_found++;
420 prev_thread_ptr = thread_ptr;
421
422 /* Get the location of the next thread structure. */
423 thread_ptr = 0;
424 retval = target_read_buffer(rtos->target,
425 prev_thread_ptr + param->thread_next_offset,
426 param->pointer_width,
427 (uint8_t *) &thread_ptr);
428 if (retval != ERROR_OK) {
429 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
430 return retval;
431 }
432 }
433
434 rtos->thread_count = tasks_found;
435
436 return 0;
437 }
438
439 static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
440 struct rtos_reg **reg_list, int *num_regs)
441 {
442 int retval;
443 const struct threadx_params *param;
444
445 if (!rtos)
446 return -1;
447
448 if (!is_thread_id_valid(rtos, thread_id))
449 return -2;
450
451 if (!rtos->rtos_specific_params)
452 return -3;
453
454 param = (const struct threadx_params *) rtos->rtos_specific_params;
455
456 /* Read the stack pointer */
457 int64_t stack_ptr = 0;
458 retval = target_read_buffer(rtos->target,
459 thread_id + param->thread_stack_offset,
460 param->pointer_width,
461 (uint8_t *)&stack_ptr);
462 if (retval != ERROR_OK) {
463 LOG_ERROR("Error reading stack frame from ThreadX thread");
464 return retval;
465 }
466
467 LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
468
469 if (stack_ptr == 0) {
470 LOG_ERROR("null stack pointer in thread");
471 return -5;
472 }
473
474 const struct rtos_register_stacking *stacking_info =
475 get_stacking_info(rtos, stack_ptr);
476
477 if (!stacking_info) {
478 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
479 return -6;
480 }
481
482 return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
483 }
484
485 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
486 {
487 unsigned int i;
488 *symbol_list = calloc(
489 ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem));
490
491 for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++)
492 (*symbol_list)[i].symbol_name = threadx_symbol_list[i];
493
494 return 0;
495 }
496
497 static bool threadx_detect_rtos(struct target *target)
498 {
499 if ((target->rtos->symbols) &&
500 (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) {
501 /* looks like ThreadX */
502 return true;
503 }
504 return false;
505 }
506
507 #if 0
508
509 static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id)
510 {
511 return 0;
512 }
513
514 static int threadx_get_thread_detail(struct rtos *rtos,
515 threadid_t thread_id,
516 struct thread_detail *detail)
517 {
518 unsigned int i = 0;
519 int retval;
520
521 #define THREADX_THREAD_NAME_STR_SIZE (200)
522 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
523
524 const struct threadx_params *param;
525
526 if (!rtos)
527 return -1;
528
529 if (thread_id == 0)
530 return -2;
531
532 if (!rtos->rtos_specific_params)
533 return -3;
534
535 param = (const struct threadx_params *) rtos->rtos_specific_params;
536
537 if (!rtos->symbols) {
538 LOG_ERROR("No symbols for ThreadX");
539 return -3;
540 }
541
542 detail->threadid = thread_id;
543
544 int64_t name_ptr = 0;
545 /* read the name pointer */
546 retval = target_read_buffer(rtos->target,
547 thread_id + param->thread_name_offset,
548 param->pointer_width,
549 (uint8_t *)&name_ptr);
550 if (retval != ERROR_OK) {
551 LOG_ERROR("Could not read ThreadX thread name pointer from target");
552 return retval;
553 }
554
555 /* Read the thread name */
556 retval = target_read_buffer(rtos->target,
557 name_ptr,
558 THREADX_THREAD_NAME_STR_SIZE,
559 (uint8_t *)&tmp_str);
560 if (retval != ERROR_OK) {
561 LOG_ERROR("Error reading thread name from ThreadX target");
562 return retval;
563 }
564 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
565
566 if (tmp_str[0] == '\x00')
567 strcpy(tmp_str, "No Name");
568
569 detail->thread_name_str = malloc(strlen(tmp_str)+1);
570
571 /* Read the thread status */
572 int64_t thread_status = 0;
573 retval =
574 target_read_buffer(rtos->target,
575 thread_id + param->thread_state_offset,
576 4,
577 (uint8_t *)&thread_status);
578 if (retval != ERROR_OK) {
579 LOG_ERROR("Error reading thread state from ThreadX target");
580 return retval;
581 }
582
583 for (i = 0; (i < THREADX_NUM_STATES) &&
584 (threadx_thread_states[i].value != thread_status); i++) {
585 /* empty */
586 }
587
588 char *state_desc;
589 if (i < THREADX_NUM_STATES)
590 state_desc = threadx_thread_states[i].desc;
591 else
592 state_desc = "Unknown state";
593
594 detail->extra_info_str = malloc(strlen(state_desc)+1);
595
596 detail->exists = true;
597
598 return 0;
599 }
600
601 #endif
602
603 static int threadx_create(struct target *target)
604 {
605 for (unsigned int i = 0; i < ARRAY_SIZE(threadx_params_list); i++)
606 if (strcmp(threadx_params_list[i].target_name, target->type->name) == 0) {
607 target->rtos->rtos_specific_params = (void *)&threadx_params_list[i];
608 target->rtos->current_thread = 0;
609 target->rtos->thread_details = NULL;
610 return 0;
611 }
612
613 LOG_ERROR("Could not find target in ThreadX compatibility list");
614 return -1;
615 }

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)