openocd: src: replace the GPL and BSD-Source-Code license tags
[fw/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, 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 }