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

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)