rtos: convert CamelCase enum in uppercase
[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 bool 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, struct rtos_reg **reg_list, int *num_regs);
42 static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *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 ARRAY_SIZE(ThreadX_thread_states)
69
70 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
71 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
72 { 0, -1, 32 }, /* r0 */
73 { 1, -1, 32 }, /* r1 */
74 { 2, -1, 32 }, /* r2 */
75 { 3, -1, 32 }, /* r3 */
76 { 4, 0x08, 32 }, /* r4 */
77 { 5, 0x0C, 32 }, /* r5 */
78 { 6, 0x10, 32 }, /* r6 */
79 { 7, 0x14, 32 }, /* r7 */
80 { 8, 0x18, 32 }, /* r8 */
81 { 9, 0x1C, 32 }, /* r9 */
82 { 10, 0x20, 32 }, /* r10 */
83 { 11, 0x24, 32 }, /* r11 */
84 { 12, -1, 32 }, /* r12 */
85 { 13, -2, 32 }, /* sp (r13) */
86 { 14, 0x28, 32 }, /* lr (r14) */
87 { 15, -1, 32 }, /* pc (r15) */
88 /*{ 16, -1, 32 },*/ /* lr (r14) */
89 /*{ 17, 0x28, 32 },*/ /* pc (r15) */
90 { 16, 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 { 0, 0x08, 32 }, /* r0 */
95 { 1, 0x0C, 32 }, /* r1 */
96 { 2, 0x10, 32 }, /* r2 */
97 { 3, 0x14, 32 }, /* r3 */
98 { 4, 0x18, 32 }, /* r4 */
99 { 5, 0x1C, 32 }, /* r5 */
100 { 6, 0x20, 32 }, /* r6 */
101 { 7, 0x24, 32 }, /* r7 */
102 { 8, 0x28, 32 }, /* r8 */
103 { 9, 0x2C, 32 }, /* r9 */
104 { 10, 0x30, 32 }, /* r10 */
105 { 11, 0x34, 32 }, /* r11 */
106 { 12, 0x38, 32 }, /* r12 */
107 { 13, -2, 32 }, /* sp (r13) */
108 { 14, 0x3C, 32 }, /* lr (r14) */
109 { 15, 0x40, 32 }, /* pc (r15) */
110 { 16, 0x04, 32 }, /* xPSR */
111 };
112
113 static 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 enum ThreadX_symbol_values {
183 THREADX_VAL_TX_THREAD_CURRENT_PTR = 0,
184 THREADX_VAL_TX_THREAD_CREATED_PTR = 1,
185 THREADX_VAL_TX_THREAD_CREATED_COUNT = 2,
186 };
187
188 static const char * const ThreadX_symbol_list[] = {
189 "_tx_thread_current_ptr",
190 "_tx_thread_created_ptr",
191 "_tx_thread_created_count",
192 NULL
193 };
194
195 const struct rtos_type ThreadX_rtos = {
196 .name = "ThreadX",
197
198 .detect_rtos = ThreadX_detect_rtos,
199 .create = ThreadX_create,
200 .update_threads = ThreadX_update_threads,
201 .get_thread_reg_list = ThreadX_get_thread_reg_list,
202 .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup,
203 };
204
205 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
206 {
207 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
208
209 if (param->fn_get_stacking_info != NULL)
210 return param->fn_get_stacking_info(rtos, stack_ptr);
211
212 return param->stacking_info + 0;
213 }
214
215 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
216 {
217 const struct ThreadX_params *param;
218
219 if (rtos->rtos_specific_params == NULL)
220 return 0; /* invalid */
221
222 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
223
224 if (param->fn_is_thread_id_valid != NULL)
225 return param->fn_is_thread_id_valid(rtos, thread_id);
226
227 return (thread_id != 0);
228 }
229
230 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
231 {
232 const struct ThreadX_params *param = (const struct ThreadX_params *) rtos->rtos_specific_params;
233 int retval;
234 uint32_t flag;
235
236 retval = target_read_buffer(rtos->target,
237 stack_ptr,
238 sizeof(flag),
239 (uint8_t *)&flag);
240 if (retval != ERROR_OK) {
241 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
242 return NULL;
243 }
244
245 if (flag == 0) {
246 LOG_DEBUG(" solicited stack");
247 return param->stacking_info + 0;
248 } else {
249 LOG_DEBUG(" interrupt stack: %" PRIu32, flag);
250 return param->stacking_info + 1;
251 }
252 }
253
254 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
255 {
256 return (thread_id != 0 && thread_id != 1);
257 }
258
259 static int ThreadX_update_threads(struct rtos *rtos)
260 {
261 int retval;
262 int tasks_found = 0;
263 int thread_list_size = 0;
264 const struct ThreadX_params *param;
265
266 if (rtos == NULL)
267 return -1;
268
269 if (rtos->rtos_specific_params == NULL)
270 return -3;
271
272 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
273
274 if (rtos->symbols == NULL) {
275 LOG_ERROR("No symbols for ThreadX");
276 return -4;
277 }
278
279 if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) {
280 LOG_ERROR("Don't have the number of threads in ThreadX");
281 return -2;
282 }
283
284 /* read the number of threads */
285 retval = target_read_buffer(rtos->target,
286 rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address,
287 4,
288 (uint8_t *)&thread_list_size);
289
290 if (retval != ERROR_OK) {
291 LOG_ERROR("Could not read ThreadX thread count from target");
292 return retval;
293 }
294
295 /* wipe out previous thread details if any */
296 rtos_free_threadlist(rtos);
297
298 /* read the current thread id */
299 retval = target_read_buffer(rtos->target,
300 rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address,
301 4,
302 (uint8_t *)&rtos->current_thread);
303
304 if (retval != ERROR_OK) {
305 LOG_ERROR("Could not read ThreadX current thread from target");
306 return retval;
307 }
308
309 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
310 /* Either : No RTOS threads - there is always at least the current execution though */
311 /* OR : No current thread - all threads suspended - show the current execution
312 * of idling */
313 char tmp_str[] = "Current Execution";
314 thread_list_size++;
315 tasks_found++;
316 rtos->thread_details = malloc(
317 sizeof(struct thread_detail) * thread_list_size);
318 rtos->thread_details->threadid = 1;
319 rtos->thread_details->exists = true;
320 rtos->thread_details->extra_info_str = NULL;
321 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
322 strcpy(rtos->thread_details->thread_name_str, tmp_str);
323
324 if (thread_list_size == 0) {
325 rtos->thread_count = 1;
326 return ERROR_OK;
327 }
328 } else {
329 /* create space for new thread details */
330 rtos->thread_details = malloc(
331 sizeof(struct thread_detail) * thread_list_size);
332 }
333
334 /* Read the pointer to the first thread */
335 int64_t thread_ptr = 0;
336 retval = target_read_buffer(rtos->target,
337 rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address,
338 param->pointer_width,
339 (uint8_t *)&thread_ptr);
340 if (retval != ERROR_OK) {
341 LOG_ERROR("Could not read ThreadX thread location from target");
342 return retval;
343 }
344
345 /* loop over all threads */
346 int64_t prev_thread_ptr = 0;
347 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
348
349 #define THREADX_THREAD_NAME_STR_SIZE (200)
350 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
351 unsigned int i = 0;
352 int64_t name_ptr = 0;
353
354 /* Save the thread pointer */
355 rtos->thread_details[tasks_found].threadid = thread_ptr;
356
357 /* read the name pointer */
358 retval = target_read_buffer(rtos->target,
359 thread_ptr + param->thread_name_offset,
360 param->pointer_width,
361 (uint8_t *)&name_ptr);
362 if (retval != ERROR_OK) {
363 LOG_ERROR("Could not read ThreadX thread name pointer from target");
364 return retval;
365 }
366
367 /* Read the thread name */
368 retval =
369 target_read_buffer(rtos->target,
370 name_ptr,
371 THREADX_THREAD_NAME_STR_SIZE,
372 (uint8_t *)&tmp_str);
373 if (retval != ERROR_OK) {
374 LOG_ERROR("Error reading thread name from ThreadX target");
375 return retval;
376 }
377 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
378
379 if (tmp_str[0] == '\x00')
380 strcpy(tmp_str, "No Name");
381
382 rtos->thread_details[tasks_found].thread_name_str =
383 malloc(strlen(tmp_str)+1);
384 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
385
386 /* Read the thread status */
387 int64_t thread_status = 0;
388 retval = target_read_buffer(rtos->target,
389 thread_ptr + param->thread_state_offset,
390 4,
391 (uint8_t *)&thread_status);
392 if (retval != ERROR_OK) {
393 LOG_ERROR("Error reading thread state from ThreadX target");
394 return retval;
395 }
396
397 for (i = 0; (i < THREADX_NUM_STATES) &&
398 (ThreadX_thread_states[i].value != thread_status); i++) {
399 /* empty */
400 }
401
402 const char *state_desc;
403 if (i < THREADX_NUM_STATES)
404 state_desc = ThreadX_thread_states[i].desc;
405 else
406 state_desc = "Unknown state";
407
408 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
409 state_desc)+8);
410 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
411
412 rtos->thread_details[tasks_found].exists = true;
413
414 tasks_found++;
415 prev_thread_ptr = thread_ptr;
416
417 /* Get the location of the next thread structure. */
418 thread_ptr = 0;
419 retval = target_read_buffer(rtos->target,
420 prev_thread_ptr + param->thread_next_offset,
421 param->pointer_width,
422 (uint8_t *) &thread_ptr);
423 if (retval != ERROR_OK) {
424 LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
425 return retval;
426 }
427 }
428
429 rtos->thread_count = tasks_found;
430
431 return 0;
432 }
433
434 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
435 struct rtos_reg **reg_list, int *num_regs)
436 {
437 int retval;
438 const struct ThreadX_params *param;
439
440 if (rtos == NULL)
441 return -1;
442
443 if (!is_thread_id_valid(rtos, thread_id))
444 return -2;
445
446 if (rtos->rtos_specific_params == NULL)
447 return -3;
448
449 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
450
451 /* Read the stack pointer */
452 int64_t stack_ptr = 0;
453 retval = target_read_buffer(rtos->target,
454 thread_id + param->thread_stack_offset,
455 param->pointer_width,
456 (uint8_t *)&stack_ptr);
457 if (retval != ERROR_OK) {
458 LOG_ERROR("Error reading stack frame from ThreadX thread");
459 return retval;
460 }
461
462 LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
463
464 if (stack_ptr == 0) {
465 LOG_ERROR("null stack pointer in thread");
466 return -5;
467 }
468
469 const struct rtos_register_stacking *stacking_info =
470 get_stacking_info(rtos, stack_ptr);
471
472 if (stacking_info == NULL) {
473 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
474 return -6;
475 }
476
477 return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
478 }
479
480 static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
481 {
482 unsigned int i;
483 *symbol_list = calloc(
484 ARRAY_SIZE(ThreadX_symbol_list), sizeof(struct symbol_table_elem));
485
486 for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++)
487 (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
488
489 return 0;
490 }
491
492 static bool ThreadX_detect_rtos(struct target *target)
493 {
494 if ((target->rtos->symbols != NULL) &&
495 (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) {
496 /* looks like ThreadX */
497 return true;
498 }
499 return false;
500 }
501
502 #if 0
503
504 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id)
505 {
506 return 0;
507 }
508
509 static int ThreadX_get_thread_detail(struct rtos *rtos,
510 threadid_t thread_id,
511 struct thread_detail *detail)
512 {
513 unsigned int i = 0;
514 int retval;
515
516 #define THREADX_THREAD_NAME_STR_SIZE (200)
517 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
518
519 const struct ThreadX_params *param;
520
521 if (rtos == NULL)
522 return -1;
523
524 if (thread_id == 0)
525 return -2;
526
527 if (rtos->rtos_specific_params == NULL)
528 return -3;
529
530 param = (const struct ThreadX_params *) rtos->rtos_specific_params;
531
532 if (rtos->symbols == NULL) {
533 LOG_ERROR("No symbols for ThreadX");
534 return -3;
535 }
536
537 detail->threadid = thread_id;
538
539 int64_t name_ptr = 0;
540 /* read the name pointer */
541 retval = target_read_buffer(rtos->target,
542 thread_id + param->thread_name_offset,
543 param->pointer_width,
544 (uint8_t *)&name_ptr);
545 if (retval != ERROR_OK) {
546 LOG_ERROR("Could not read ThreadX thread name pointer from target");
547 return retval;
548 }
549
550 /* Read the thread name */
551 retval = target_read_buffer(rtos->target,
552 name_ptr,
553 THREADX_THREAD_NAME_STR_SIZE,
554 (uint8_t *)&tmp_str);
555 if (retval != ERROR_OK) {
556 LOG_ERROR("Error reading thread name from ThreadX target");
557 return retval;
558 }
559 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
560
561 if (tmp_str[0] == '\x00')
562 strcpy(tmp_str, "No Name");
563
564 detail->thread_name_str = malloc(strlen(tmp_str)+1);
565
566 /* Read the thread status */
567 int64_t thread_status = 0;
568 retval =
569 target_read_buffer(rtos->target,
570 thread_id + param->thread_state_offset,
571 4,
572 (uint8_t *)&thread_status);
573 if (retval != ERROR_OK) {
574 LOG_ERROR("Error reading thread state from ThreadX target");
575 return retval;
576 }
577
578 for (i = 0; (i < THREADX_NUM_STATES) &&
579 (ThreadX_thread_states[i].value != thread_status); i++) {
580 /* empty */
581 }
582
583 char *state_desc;
584 if (i < THREADX_NUM_STATES)
585 state_desc = ThreadX_thread_states[i].desc;
586 else
587 state_desc = "Unknown state";
588
589 detail->extra_info_str = malloc(strlen(state_desc)+1);
590
591 detail->exists = true;
592
593 return 0;
594 }
595
596 #endif
597
598 static int ThreadX_create(struct target *target)
599 {
600 for (unsigned int i = 0; i < ARRAY_SIZE(ThreadX_params_list); i++)
601 if (strcmp(ThreadX_params_list[i].target_name, target->type->name) == 0) {
602 target->rtos->rtos_specific_params = (void *)&ThreadX_params_list[i];
603 target->rtos->current_thread = 0;
604 target->rtos->thread_details = NULL;
605 return 0;
606 }
607
608 LOG_ERROR("Could not find target in ThreadX compatibility list");
609 return -1;
610 }

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)