]> git.sur5r.net Git - openocd/blob - src/rtos/ThreadX.c
b7dbe6d1111bdf057d8f78c1a34cd4d7ae1e7f8a
[openocd] / 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, 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 bool 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 true;
501         }
502         return false;
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 }