arm_adi_v5: describe Class 0x9 Device Architecture register
[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 .stack_registers_size = ARM926EJS_REGISTERS_SIZE_SOLICITED,
116 .stack_growth_direction = -1,
117 .num_output_registers = 17,
118 .register_offsets = rtos_threadx_arm926ejs_stack_offsets_solicited
119 },
120 {
121 .stack_registers_size = ARM926EJS_REGISTERS_SIZE_INTERRUPT,
122 .stack_growth_direction = -1,
123 .num_output_registers = 17,
124 .register_offsets = rtos_threadx_arm926ejs_stack_offsets_interrupt
125 },
126 };
127
128 struct threadx_params {
129 const char *target_name;
130 unsigned char pointer_width;
131 unsigned char thread_stack_offset;
132 unsigned char thread_name_offset;
133 unsigned char thread_state_offset;
134 unsigned char thread_next_offset;
135 const struct rtos_register_stacking *stacking_info;
136 size_t stacking_info_nb;
137 const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr);
138 int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id);
139 };
140
141 static const struct threadx_params threadx_params_list[] = {
142 {
143 "cortex_m", /* target_name */
144 4, /* pointer_width; */
145 8, /* thread_stack_offset; */
146 40, /* thread_name_offset; */
147 48, /* thread_state_offset; */
148 136, /* thread_next_offset */
149 &rtos_standard_cortex_m3_stacking, /* stacking_info */
150 1, /* stacking_info_nb */
151 NULL, /* fn_get_stacking_info */
152 NULL, /* fn_is_thread_id_valid */
153 },
154 {
155 "cortex_r4", /* target_name */
156 4, /* pointer_width; */
157 8, /* thread_stack_offset; */
158 40, /* thread_name_offset; */
159 48, /* thread_state_offset; */
160 136, /* thread_next_offset */
161 &rtos_standard_cortex_r4_stacking, /* stacking_info */
162 1, /* stacking_info_nb */
163 NULL, /* fn_get_stacking_info */
164 NULL, /* fn_is_thread_id_valid */
165 },
166 {
167 "arm926ejs", /* target_name */
168 4, /* pointer_width; */
169 8, /* thread_stack_offset; */
170 40, /* thread_name_offset; */
171 48, /* thread_state_offset; */
172 136, /* thread_next_offset */
173 rtos_threadx_arm926ejs_stacking, /* stacking_info */
174 2, /* stacking_info_nb */
175 get_stacking_info_arm926ejs, /* fn_get_stacking_info */
176 is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */
177 },
178 {
179 "hla_target", /* target_name */
180 4, /* pointer_width; */
181 8, /* thread_stack_offset; */
182 40, /* thread_name_offset; */
183 48, /* thread_state_offset; */
184 136, /* thread_next_offset */
185 &rtos_standard_cortex_m3_stacking, /* stacking_info */
186 1, /* stacking_info_nb */
187 NULL, /* fn_get_stacking_info */
188 NULL, /* fn_is_thread_id_valid */
189 },
190 };
191
192 enum threadx_symbol_values {
193 THREADX_VAL_TX_THREAD_CURRENT_PTR = 0,
194 THREADX_VAL_TX_THREAD_CREATED_PTR = 1,
195 THREADX_VAL_TX_THREAD_CREATED_COUNT = 2,
196 };
197
198 static const char * const threadx_symbol_list[] = {
199 "_tx_thread_current_ptr",
200 "_tx_thread_created_ptr",
201 "_tx_thread_created_count",
202 NULL
203 };
204
205 const struct rtos_type threadx_rtos = {
206 .name = "ThreadX",
207
208 .detect_rtos = threadx_detect_rtos,
209 .create = threadx_create,
210 .update_threads = threadx_update_threads,
211 .get_thread_reg_list = threadx_get_thread_reg_list,
212 .get_symbol_list_to_lookup = threadx_get_symbol_list_to_lookup,
213 };
214
215 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
216 {
217 const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
218
219 if (param->fn_get_stacking_info)
220 return param->fn_get_stacking_info(rtos, stack_ptr);
221
222 return param->stacking_info + 0;
223 }
224
225 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
226 {
227 const struct threadx_params *param;
228
229 if (!rtos->rtos_specific_params)
230 return 0; /* invalid */
231
232 param = (const struct threadx_params *) rtos->rtos_specific_params;
233
234 if (param->fn_is_thread_id_valid)
235 return param->fn_is_thread_id_valid(rtos, thread_id);
236
237 return (thread_id != 0);
238 }
239
240 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
241 {
242 const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
243 int retval;
244 uint32_t flag;
245
246 retval = target_read_buffer(rtos->target,
247 stack_ptr,
248 sizeof(flag),
249 (uint8_t *)&flag);
250 if (retval != ERROR_OK) {
251 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
252 return NULL;
253 }
254
255 if (flag == 0) {
256 LOG_DEBUG(" solicited stack");
257 return param->stacking_info + 0;
258 } else {
259 LOG_DEBUG(" interrupt stack: %" PRIu32, flag);
260 return param->stacking_info + 1;
261 }
262 }
263
264 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
265 {
266 return (thread_id != 0 && thread_id != 1);
267 }
268
269 static int threadx_update_threads(struct rtos *rtos)
270 {
271 int retval;
272 int tasks_found = 0;
273 int thread_list_size = 0;
274 const struct threadx_params *param;
275
276 if (!rtos)
277 return -1;
278
279 if (!rtos->rtos_specific_params)
280 return -3;
281
282 param = (const struct threadx_params *) rtos->rtos_specific_params;
283
284 if (!rtos->symbols) {
285 LOG_ERROR("No symbols for ThreadX");
286 return -4;
287 }
288
289 if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) {
290 LOG_ERROR("Don't have the number of threads in ThreadX");
291 return -2;
292 }
293
294 /* read the number of threads */
295 retval = target_read_buffer(rtos->target,
296 rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address,
297 4,
298 (uint8_t *)&thread_list_size);
299
300 if (retval != ERROR_OK) {
301 LOG_ERROR("Could not read ThreadX thread count from target");
302 return retval;
303 }
304
305 /* wipe out previous thread details if any */
306 rtos_free_threadlist(rtos);
307
308 /* read the current thread id */
309 retval = target_read_buffer(rtos->target,
310 rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address,
311 4,
312 (uint8_t *)&rtos->current_thread);
313
314 if (retval != ERROR_OK) {
315 LOG_ERROR("Could not read ThreadX current thread from target");
316 return retval;
317 }
318
319 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
320 /* Either : No RTOS threads - there is always at least the current execution though */
321 /* OR : No current thread - all threads suspended - show the current execution
322 * of idling */
323 char tmp_str[] = "Current Execution";
324 thread_list_size++;
325 tasks_found++;
326 rtos->thread_details = malloc(
327 sizeof(struct thread_detail) * thread_list_size);
328 rtos->thread_details->threadid = 1;
329 rtos->thread_details->exists = true;
330 rtos->thread_details->extra_info_str = NULL;
331 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
332 strcpy(rtos->thread_details->thread_name_str, tmp_str);
333
334 if (thread_list_size == 0) {
335 rtos->thread_count = 1;
336 return ERROR_OK;
337 }
338 } else {
339 /* create space for new thread details */
340 rtos->thread_details = malloc(
341 sizeof(struct thread_detail) * thread_list_size);
342 }
343
344 /* Read the pointer to the first thread */
345 int64_t thread_ptr = 0;
346 retval = target_read_buffer(rtos->target,
347 rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address,
348 param->pointer_width,
349 (uint8_t *)&thread_ptr);
350 if (retval != ERROR_OK) {
351 LOG_ERROR("Could not read ThreadX thread location from target");
352 return retval;
353 }
354
355 /* loop over all threads */
356 int64_t prev_thread_ptr = 0;
357 while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
358
359 #define THREADX_THREAD_NAME_STR_SIZE (200)
360 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
361 unsigned int i = 0;
362 int64_t name_ptr = 0;
363
364 /* Save the thread pointer */
365 rtos->thread_details[tasks_found].threadid = thread_ptr;
366
367 /* read the name pointer */
368 retval = target_read_buffer(rtos->target,
369 thread_ptr + param->thread_name_offset,
370 param->pointer_width,
371 (uint8_t *)&name_ptr);
372 if (retval != ERROR_OK) {
373 LOG_ERROR("Could not read ThreadX thread name pointer from target");
374 return retval;
375 }
376
377 /* Read the thread name */
378 retval =
379 target_read_buffer(rtos->target,
380 name_ptr,
381 THREADX_THREAD_NAME_STR_SIZE,
382 (uint8_t *)&tmp_str);
383 if (retval != ERROR_OK) {
384 LOG_ERROR("Error reading thread name from ThreadX target");
385 return retval;
386 }
387 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
388
389 if (tmp_str[0] == '\x00')
390 strcpy(tmp_str, "No Name");
391
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);
395
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,
400 4,
401 (uint8_t *)&thread_status);
402 if (retval != ERROR_OK) {
403 LOG_ERROR("Error reading thread state from ThreadX target");
404 return retval;
405 }
406
407 for (i = 0; (i < THREADX_NUM_STATES) &&
408 (threadx_thread_states[i].value != thread_status); i++) {
409 /* empty */
410 }
411
412 const char *state_desc;
413 if (i < THREADX_NUM_STATES)
414 state_desc = threadx_thread_states[i].desc;
415 else
416 state_desc = "Unknown state";
417
418 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
419 state_desc)+8);
420 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
421
422 rtos->thread_details[tasks_found].exists = true;
423
424 tasks_found++;
425 prev_thread_ptr = thread_ptr;
426
427 /* Get the location of the next thread structure. */
428 thread_ptr = 0;
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");
435 return retval;
436 }
437 }
438
439 rtos->thread_count = tasks_found;
440
441 return 0;
442 }
443
444 static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
445 struct rtos_reg **reg_list, int *num_regs)
446 {
447 int retval;
448 const struct threadx_params *param;
449
450 if (!rtos)
451 return -1;
452
453 if (!is_thread_id_valid(rtos, thread_id))
454 return -2;
455
456 if (!rtos->rtos_specific_params)
457 return -3;
458
459 param = (const struct threadx_params *) rtos->rtos_specific_params;
460
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");
469 return retval;
470 }
471
472 LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
473
474 if (stack_ptr == 0) {
475 LOG_ERROR("null stack pointer in thread");
476 return -5;
477 }
478
479 const struct rtos_register_stacking *stacking_info =
480 get_stacking_info(rtos, stack_ptr);
481
482 if (!stacking_info) {
483 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
484 return -6;
485 }
486
487 return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
488 }
489
490 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
491 {
492 unsigned int i;
493 *symbol_list = calloc(
494 ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem));
495
496 for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++)
497 (*symbol_list)[i].symbol_name = threadx_symbol_list[i];
498
499 return 0;
500 }
501
502 static bool threadx_detect_rtos(struct target *target)
503 {
504 if ((target->rtos->symbols) &&
505 (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) {
506 /* looks like ThreadX */
507 return true;
508 }
509 return false;
510 }
511
512 #if 0
513
514 static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id)
515 {
516 return 0;
517 }
518
519 static int threadx_get_thread_detail(struct rtos *rtos,
520 threadid_t thread_id,
521 struct thread_detail *detail)
522 {
523 unsigned int i = 0;
524 int retval;
525
526 #define THREADX_THREAD_NAME_STR_SIZE (200)
527 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
528
529 const struct threadx_params *param;
530
531 if (!rtos)
532 return -1;
533
534 if (thread_id == 0)
535 return -2;
536
537 if (!rtos->rtos_specific_params)
538 return -3;
539
540 param = (const struct threadx_params *) rtos->rtos_specific_params;
541
542 if (!rtos->symbols) {
543 LOG_ERROR("No symbols for ThreadX");
544 return -3;
545 }
546
547 detail->threadid = thread_id;
548
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");
557 return retval;
558 }
559
560 /* Read the thread name */
561 retval = target_read_buffer(rtos->target,
562 name_ptr,
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");
567 return retval;
568 }
569 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
570
571 if (tmp_str[0] == '\x00')
572 strcpy(tmp_str, "No Name");
573
574 detail->thread_name_str = malloc(strlen(tmp_str)+1);
575
576 /* Read the thread status */
577 int64_t thread_status = 0;
578 retval =
579 target_read_buffer(rtos->target,
580 thread_id + param->thread_state_offset,
581 4,
582 (uint8_t *)&thread_status);
583 if (retval != ERROR_OK) {
584 LOG_ERROR("Error reading thread state from ThreadX target");
585 return retval;
586 }
587
588 for (i = 0; (i < THREADX_NUM_STATES) &&
589 (threadx_thread_states[i].value != thread_status); i++) {
590 /* empty */
591 }
592
593 char *state_desc;
594 if (i < THREADX_NUM_STATES)
595 state_desc = threadx_thread_states[i].desc;
596 else
597 state_desc = "Unknown state";
598
599 detail->extra_info_str = malloc(strlen(state_desc)+1);
600
601 detail->exists = true;
602
603 return 0;
604 }
605
606 #endif
607
608 static int threadx_create(struct target *target)
609 {
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;
615 return 0;
616 }
617
618 LOG_ERROR("Could not find target in ThreadX compatibility list");
619 return -1;
620 }

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)