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