ab8a66e93b262627a6e75e78fa4a67c4dc0a9013
[openocd.git] / src / rtos / ThreadX.c
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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "rtos.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_standard_stackings.h"
31
32 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr);
33 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr);
34
35 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id);
36 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id);
37
38 static int ThreadX_detect_rtos(struct target *target);
39 static int ThreadX_create(struct target *target);
40 static int ThreadX_update_threads(struct rtos *rtos);
41 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
42 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
43
44
45
46 struct ThreadX_thread_state {
47 int value;
48 const char *desc;
49 };
50
51 static const struct ThreadX_thread_state ThreadX_thread_states[] = {
52 { 0, "Ready" },
53 { 1, "Completed" },
54 { 2, "Terminated" },
55 { 3, "Suspended" },
56 { 4, "Sleeping" },
57 { 5, "Waiting - Queue" },
58 { 6, "Waiting - Semaphore" },
59 { 7, "Waiting - Event flag" },
60 { 8, "Waiting - Memory" },
61 { 9, "Waiting - Memory" },
62 { 10, "Waiting - I/O" },
63 { 11, "Waiting - Filesystem" },
64 { 12, "Waiting - Network" },
65 { 13, "Waiting - Mutex" },
66 };
67
68 #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
69
70 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
71 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
72 { -1, 32 }, /* r0 */
73 { -1, 32 }, /* r1 */
74 { -1, 32 }, /* r2 */
75 { -1, 32 }, /* r3 */
76 { 0x08, 32 }, /* r4 */
77 { 0x0C, 32 }, /* r5 */
78 { 0x10, 32 }, /* r6 */
79 { 0x14, 32 }, /* r7 */
80 { 0x18, 32 }, /* r8 */
81 { 0x1C, 32 }, /* r9 */
82 { 0x20, 32 }, /* r10 */
83 { 0x24, 32 }, /* r11 */
84 { -1, 32 }, /* r12 */
85 { -2, 32 }, /* sp (r13) */
86 { 0x28, 32 }, /* lr (r14) */
87 { -1, 32 }, /* pc (r15) */
88 /*{ -1, 32 },*/ /* lr (r14) */
89 /*{ 0x28, 32 },*/ /* pc (r15) */
90 { 0x04, 32 }, /* xPSR */
91 };
92 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
93 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = {
94 { 0x08, 32 }, /* r0 */
95 { 0x0C, 32 }, /* r1 */
96 { 0x10, 32 }, /* r2 */
97 { 0x14, 32 }, /* r3 */
98 { 0x18, 32 }, /* r4 */
99 { 0x1C, 32 }, /* r5 */
100 { 0x20, 32 }, /* r6 */
101 { 0x24, 32 }, /* r7 */
102 { 0x28, 32 }, /* r8 */
103 { 0x2C, 32 }, /* r9 */
104 { 0x30, 32 }, /* r10 */
105 { 0x34, 32 }, /* r11 */
106 { 0x38, 32 }, /* r12 */
107 { -2, 32 }, /* sp (r13) */
108 { 0x3C, 32 }, /* lr (r14) */
109 { 0x40, 32 }, /* pc (r15) */
110 { 0x04, 32 }, /* xPSR */
111 };
112
113 const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
114 {
115 ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */
116 -1, /* stack_growth_direction */
117 17, /* num_output_registers */
118 NULL, /* stack_alignment */
119 rtos_threadx_arm926ejs_stack_offsets_solicited /* register_offsets */
120 },
121 {
122 ARM926EJS_REGISTERS_SIZE_INTERRUPT, /* stack_registers_size */
123 -1, /* stack_growth_direction */
124 17, /* num_output_registers */
125 NULL, /* stack_alignment */
126 rtos_threadx_arm926ejs_stack_offsets_interrupt /* register_offsets */
127 },
128 };
129
130 struct ThreadX_params {
131 const char *target_name;
132 unsigned char pointer_width;
133 unsigned char thread_stack_offset;
134 unsigned char thread_name_offset;
135 unsigned char thread_state_offset;
136 unsigned char thread_next_offset;
137 const struct rtos_register_stacking *stacking_info;
138 size_t stacking_info_nb;
139 const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr);
140 int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id);
141 };
142
143 static const struct ThreadX_params ThreadX_params_list[] = {
144 {
145 "cortex_m", /* target_name */
146 4, /* pointer_width; */
147 8, /* thread_stack_offset; */
148 40, /* thread_name_offset; */
149 48, /* thread_state_offset; */
150 136, /* thread_next_offset */
151 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
152 1, /* stacking_info_nb */
153 NULL, /* fn_get_stacking_info */
154 NULL, /* fn_is_thread_id_valid */
155 },
156 {
157 "cortex_r4", /* target_name */
158 4, /* pointer_width; */
159 8, /* thread_stack_offset; */
160 40, /* thread_name_offset; */
161 48, /* thread_state_offset; */
162 136, /* thread_next_offset */
163 &rtos_standard_Cortex_R4_stacking, /* stacking_info */
164 1, /* stacking_info_nb */
165 NULL, /* fn_get_stacking_info */
166 NULL, /* fn_is_thread_id_valid */
167 },
168 {
169 "arm926ejs", /* target_name */
170 4, /* pointer_width; */
171 8, /* thread_stack_offset; */
172 40, /* thread_name_offset; */
173 48, /* thread_state_offset; */
174 136, /* thread_next_offset */
175 rtos_threadx_arm926ejs_stacking, /* stacking_info */
176 2, /* stacking_info_nb */
177 get_stacking_info_arm926ejs, /* fn_get_stacking_info */
178 is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */
179 },
180 };
181
182 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
183
184 enum ThreadX_symbol_values {
185 ThreadX_VAL_tx_thread_current_ptr = 0,
186 ThreadX_VAL_tx_thread_created_ptr = 1,
187 ThreadX_VAL_tx_thread_created_count = 2,
188 };
189
190 static const char * const ThreadX_symbol_list[] = {
191 "_tx_thread_current_ptr",
192 "_tx_thread_created_ptr",
193 "_tx_thread_created_count",
194 NULL
195 };
196
197 const struct rtos_type ThreadX_rtos = {
198 .name = "ThreadX",
199
200 .detect_rtos = ThreadX_detect_rtos,
201 .create = ThreadX_create,
202 .update_threads = ThreadX_update_threads,
203 .get_thread_reg_list = ThreadX_get_thread_reg_list,
204 .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup,
205 };
206
207 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
208 {
209 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
210
211 if (param->fn_get_stacking_info != NULL)
212 return param->fn_get_stacking_info(rtos, stack_ptr);
213
214 return param->stacking_info + 0;
215 }
216
217 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
218 {
219 const struct ThreadX_params *param;
220
221 if (rtos->rtos_specific_params == NULL)
222 return 0; /* invalid */
223
224 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
225
226 if (param->fn_is_thread_id_valid != NULL)
227 return param->fn_is_thread_id_valid(rtos, thread_id);
228
229 return (thread_id != 0);
230 }
231
232 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
233 {
234 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
235 int retval;
236 uint32_t flag;
237
238 retval = target_read_buffer(rtos->target,
239 stack_ptr,
240 sizeof(flag),
241 (uint8_t *)&flag);
242 if (retval != ERROR_OK) {
243 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
244 return NULL;
245 }
246
247 if (flag == 0) {
248 LOG_DEBUG(" solicited stack");
249 return param->stacking_info + 0;
250 } else {
251 LOG_DEBUG(" interrupt stack: %u", flag);
252 return param->stacking_info + 1;
253 }
254 }
255
256 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
257 {
258 return (thread_id != 0 && thread_id != 1);
259 }
260
261 static int ThreadX_update_threads(struct rtos *rtos)
262 {
263 int retval;
264 int tasks_found = 0;
265 int thread_list_size = 0;
266 const struct ThreadX_params *param;
267
268 if (rtos == NULL)
269 return -1;
270
271 if (rtos->rtos_specific_params == NULL)
272 return -3;
273
274 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
275
276 if (rtos->symbols == NULL) {
277 LOG_ERROR("No symbols for ThreadX");
278 return -4;
279 }
280
281 if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) {
282 LOG_ERROR("Don't have the number of threads in ThreadX");
283 return -2;
284 }
285
286 /* read the number of threads */
287 retval = target_read_buffer(rtos->target,
288 rtos->symbols[ThreadX_VAL_tx_thread_created_count].address,
289 4,
290 (uint8_t *)&thread_list_size);
291
292 if (retval != ERROR_OK) {
293 LOG_ERROR("Could not read ThreadX thread count from target");
294 return retval;
295 }
296
297 /* wipe out previous thread details if any */
298 rtos_free_threadlist(rtos);
299
300 /* read the current thread id */
301 retval = target_read_buffer(rtos->target,
302 rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address,
303 4,
304 (uint8_t *)&rtos->current_thread);
305
306 if (retval != ERROR_OK) {
307 LOG_ERROR("Could not read ThreadX current thread from target");
308 return retval;
309 }
310
311 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
312 /* Either : No RTOS threads - there is always at least the current execution though */
313 /* OR : No current thread - all threads suspended - show the current execution
314 * of idling */
315 char tmp_str[] = "Current Execution";
316 thread_list_size++;
317 tasks_found++;
318 rtos->thread_details = malloc(
319 sizeof(struct thread_detail) * thread_list_size);
320 rtos->thread_details->threadid = 1;
321 rtos->thread_details->exists = true;
322 rtos->thread_details->extra_info_str = NULL;
323 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
324 strcpy(rtos->thread_details->thread_name_str, tmp_str);
325
326 if (thread_list_size == 0) {
327 rtos->thread_count = 1;
328 return ERROR_OK;
329 }
330 } else {
331 /* create space for new thread details */
332 rtos->thread_details = malloc(
333 sizeof(struct thread_detail) * thread_list_size);
334 }
335
336 /* Read the pointer to the first thread */
337 int64_t thread_ptr = 0;
338 retval = target_read_buffer(rtos->target,
339 rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address,
340 param->pointer_width,
341 (uint8_t *)&thread_ptr);
342 if (retval != ERROR_OK) {
343 LOG_ERROR("Could not read ThreadX thread location from target");
344 return retval;
345 }
346
347 /* loop over all threads */
348 int64_t prev_thread_ptr = 0;
349 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
350
351 #define THREADX_THREAD_NAME_STR_SIZE (200)
352 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
353 unsigned int i = 0;
354 int64_t name_ptr = 0;
355
356 /* Save the thread pointer */
357 rtos->thread_details[tasks_found].threadid = thread_ptr;
358
359 /* read the name pointer */
360 retval = target_read_buffer(rtos->target,
361 thread_ptr + param->thread_name_offset,
362 param->pointer_width,
363 (uint8_t *)&name_ptr);
364 if (retval != ERROR_OK) {
365 LOG_ERROR("Could not read ThreadX thread name pointer from target");
366 return retval;
367 }
368
369 /* Read the thread name */
370 retval =
371 target_read_buffer(rtos->target,
372 name_ptr,
373 THREADX_THREAD_NAME_STR_SIZE,
374 (uint8_t *)&tmp_str);
375 if (retval != ERROR_OK) {
376 LOG_ERROR("Error reading thread name from ThreadX target");
377 return retval;
378 }
379 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
380
381 if (tmp_str[0] == '\x00')
382 strcpy(tmp_str, "No Name");
383
384 rtos->thread_details[tasks_found].thread_name_str =
385 malloc(strlen(tmp_str)+1);
386 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
387
388 /* Read the thread status */
389 int64_t thread_status = 0;
390 retval = target_read_buffer(rtos->target,
391 thread_ptr + param->thread_state_offset,
392 4,
393 (uint8_t *)&thread_status);
394 if (retval != ERROR_OK) {
395 LOG_ERROR("Error reading thread state from ThreadX target");
396 return retval;
397 }
398
399 for (i = 0; (i < THREADX_NUM_STATES) &&
400 (ThreadX_thread_states[i].value != thread_status); i++) {
401 /* empty */
402 }
403
404 const char *state_desc;
405 if (i < THREADX_NUM_STATES)
406 state_desc = ThreadX_thread_states[i].desc;
407 else
408 state_desc = "Unknown state";
409
410 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
411 state_desc)+8);
412 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
413
414 rtos->thread_details[tasks_found].exists = true;
415
416 tasks_found++;
417 prev_thread_ptr = thread_ptr;
418
419 /* Get the location of the next thread structure. */
420 thread_ptr = 0;
421 retval = target_read_buffer(rtos->target,
422 prev_thread_ptr + param->thread_next_offset,
423 param->pointer_width,
424 (uint8_t *) &thread_ptr);
425 if (retval != ERROR_OK) {
426 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
427 return retval;
428 }
429 }
430
431 rtos->thread_count = tasks_found;
432
433 return 0;
434 }
435
436 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
437 {
438 int retval;
439 const struct ThreadX_params *param;
440
441 *hex_reg_list = NULL;
442
443 if (rtos == NULL)
444 return -1;
445
446 if (!is_thread_id_valid(rtos, thread_id))
447 return -2;
448
449 if (rtos->rtos_specific_params == NULL)
450 return -3;
451
452 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
453
454 /* Read the stack pointer */
455 int64_t stack_ptr = 0;
456 retval = target_read_buffer(rtos->target,
457 thread_id + param->thread_stack_offset,
458 param->pointer_width,
459 (uint8_t *)&stack_ptr);
460 if (retval != ERROR_OK) {
461 LOG_ERROR("Error reading stack frame from ThreadX thread");
462 return retval;
463 }
464
465 LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
466
467 if (stack_ptr == 0) {
468 LOG_ERROR("null stack pointer in thread");
469 return -5;
470 }
471
472 const struct rtos_register_stacking *stacking_info =
473 get_stacking_info(rtos, stack_ptr);
474
475 if (stacking_info == NULL) {
476 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
477 return -6;
478 }
479
480 return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, hex_reg_list);
481 }
482
483 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
484 {
485 unsigned int i;
486 *symbol_list = calloc(
487 ARRAY_SIZE(ThreadX_symbol_list), sizeof(symbol_table_elem_t));
488
489 for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++)
490 (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
491
492 return 0;
493 }
494
495 static int ThreadX_detect_rtos(struct target *target)
496 {
497 if ((target->rtos->symbols != NULL) &&
498 (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) {
499 /* looks like ThreadX */
500 return 1;
501 }
502 return 0;
503 }
504
505 #if 0
506
507 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id)
508 {
509 return 0;
510 }
511
512 static int ThreadX_get_thread_detail(struct rtos *rtos,
513 threadid_t thread_id,
514 struct thread_detail *detail)
515 {
516 unsigned int i = 0;
517 int retval;
518
519 #define THREADX_THREAD_NAME_STR_SIZE (200)
520 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
521
522 const struct ThreadX_params *param;
523
524 if (rtos == NULL)
525 return -1;
526
527 if (thread_id == 0)
528 return -2;
529
530 if (rtos->rtos_specific_params == NULL)
531 return -3;
532
533 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
534
535 if (rtos->symbols == NULL) {
536 LOG_ERROR("No symbols for ThreadX");
537 return -3;
538 }
539
540 detail->threadid = thread_id;
541
542 int64_t name_ptr = 0;
543 /* read the name pointer */
544 retval = target_read_buffer(rtos->target,
545 thread_id + param->thread_name_offset,
546 param->pointer_width,
547 (uint8_t *)&name_ptr);
548 if (retval != ERROR_OK) {
549 LOG_ERROR("Could not read ThreadX thread name pointer from target");
550 return retval;
551 }
552
553 /* Read the thread name */
554 retval = target_read_buffer(rtos->target,
555 name_ptr,
556 THREADX_THREAD_NAME_STR_SIZE,
557 (uint8_t *)&tmp_str);
558 if (retval != ERROR_OK) {
559 LOG_ERROR("Error reading thread name from ThreadX target");
560 return retval;
561 }
562 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
563
564 if (tmp_str[0] == '\x00')
565 strcpy(tmp_str, "No Name");
566
567 detail->thread_name_str = malloc(strlen(tmp_str)+1);
568
569 /* Read the thread status */
570 int64_t thread_status = 0;
571 retval =
572 target_read_buffer(rtos->target,
573 thread_id + param->thread_state_offset,
574 4,
575 (uint8_t *)&thread_status);
576 if (retval != ERROR_OK) {
577 LOG_ERROR("Error reading thread state from ThreadX target");
578 return retval;
579 }
580
581 for (i = 0; (i < THREADX_NUM_STATES) &&
582 (ThreadX_thread_states[i].value != thread_status); i++) {
583 /* empty */
584 }
585
586 char *state_desc;
587 if (i < THREADX_NUM_STATES)
588 state_desc = ThreadX_thread_states[i].desc;
589 else
590 state_desc = "Unknown state";
591
592 detail->extra_info_str = malloc(strlen(state_desc)+1);
593
594 detail->exists = true;
595
596 return 0;
597 }
598
599 #endif
600
601 static int ThreadX_create(struct target *target)
602 {
603 int i = 0;
604 while ((i < THREADX_NUM_PARAMS) &&
605 (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) {
606 i++;
607 }
608 if (i >= THREADX_NUM_PARAMS) {
609 LOG_ERROR("Could not find target in ThreadX compatibility list");
610 return -1;
611 }
612
613 target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i];
614 target->rtos->current_thread = 0;
615 target->rtos->thread_details = NULL;
616 return 0;
617 }

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)