openocd: fix SPDX tag format for files .c
[fw/openocd] / src / rtos / ThreadX.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2011 by Broadcom Corporation                            *
5  *   Evan Hunter - ehunter@broadcom.com                                    *
6  ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos_standard_stackings.h"
20
21 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr);
22 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr);
23
24 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id);
25 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id);
26
27 static bool threadx_detect_rtos(struct target *target);
28 static int threadx_create(struct target *target);
29 static int threadx_update_threads(struct rtos *rtos);
30 static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
31 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
32
33
34
35 struct threadx_thread_state {
36         int value;
37         const char *desc;
38 };
39
40 static const struct threadx_thread_state threadx_thread_states[] = {
41         { 0,  "Ready" },
42         { 1,  "Completed" },
43         { 2,  "Terminated" },
44         { 3,  "Suspended" },
45         { 4,  "Sleeping" },
46         { 5,  "Waiting - Queue" },
47         { 6,  "Waiting - Semaphore" },
48         { 7,  "Waiting - Event flag" },
49         { 8,  "Waiting - Memory" },
50         { 9,  "Waiting - Memory" },
51         { 10, "Waiting - I/O" },
52         { 11, "Waiting - Filesystem" },
53         { 12, "Waiting - Network" },
54         { 13, "Waiting - Mutex" },
55 };
56
57 #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states)
58
59 #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
60 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
61         { 0,  -1,   32 },               /* r0        */
62         { 1,  -1,   32 },               /* r1        */
63         { 2,  -1,   32 },               /* r2        */
64         { 3,  -1,   32 },               /* r3        */
65         { 4,  0x08, 32 },               /* r4        */
66         { 5,  0x0C, 32 },               /* r5        */
67         { 6,  0x10, 32 },               /* r6        */
68         { 7,  0x14, 32 },               /* r7        */
69         { 8,  0x18, 32 },               /* r8        */
70         { 9,  0x1C, 32 },               /* r9        */
71         { 10, 0x20, 32 },               /* r10       */
72         { 11, 0x24, 32 },               /* r11       */
73         { 12, -1,   32 },               /* r12       */
74         { 13, -2,   32 },               /* sp (r13)  */
75         { 14, 0x28, 32 },               /* lr (r14)  */
76         { 15, -1,   32 },               /* pc (r15)  */
77         /*{ 16, -1,   32 },*/           /* lr (r14)  */
78         /*{ 17, 0x28, 32 },*/           /* pc (r15)  */
79         { 16, 0x04, 32 },               /* xPSR      */
80 };
81 #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
82 static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = {
83         { 0,  0x08, 32 },               /* r0        */
84         { 1,  0x0C, 32 },               /* r1        */
85         { 2,  0x10, 32 },               /* r2        */
86         { 3,  0x14, 32 },               /* r3        */
87         { 4,  0x18, 32 },               /* r4        */
88         { 5,  0x1C, 32 },               /* r5        */
89         { 6,  0x20, 32 },               /* r6        */
90         { 7,  0x24, 32 },               /* r7        */
91         { 8,  0x28, 32 },               /* r8        */
92         { 9,  0x2C, 32 },               /* r9        */
93         { 10, 0x30, 32 },               /* r10       */
94         { 11, 0x34, 32 },               /* r11       */
95         { 12, 0x38, 32 },               /* r12       */
96         { 13, -2,   32 },               /* sp (r13)  */
97         { 14, 0x3C, 32 },               /* lr (r14)  */
98         { 15, 0x40, 32 },               /* pc (r15)  */
99         { 16, 0x04, 32 },               /* xPSR      */
100 };
101
102 static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
103 {
104         .stack_registers_size = ARM926EJS_REGISTERS_SIZE_SOLICITED,
105         .stack_growth_direction = -1,
106         .num_output_registers = 17,
107         .register_offsets = rtos_threadx_arm926ejs_stack_offsets_solicited
108 },
109 {
110         .stack_registers_size = ARM926EJS_REGISTERS_SIZE_INTERRUPT,
111         .stack_growth_direction = -1,
112         .num_output_registers = 17,
113         .register_offsets = rtos_threadx_arm926ejs_stack_offsets_interrupt
114 },
115 };
116
117 struct threadx_params {
118         const char *target_name;
119         unsigned char pointer_width;
120         unsigned char thread_stack_offset;
121         unsigned char thread_name_offset;
122         unsigned char thread_state_offset;
123         unsigned char thread_next_offset;
124         const struct rtos_register_stacking *stacking_info;
125         size_t stacking_info_nb;
126         const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr);
127         int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id);
128 };
129
130 static const struct threadx_params threadx_params_list[] = {
131         {
132         "cortex_m",                             /* target_name */
133         4,                                                      /* pointer_width; */
134         8,                                                      /* thread_stack_offset; */
135         40,                                                     /* thread_name_offset; */
136         48,                                                     /* thread_state_offset; */
137         136,                                            /* thread_next_offset */
138         &rtos_standard_cortex_m3_stacking,      /* stacking_info */
139         1,                                                      /* stacking_info_nb */
140         NULL,                                           /* fn_get_stacking_info */
141         NULL,                                           /* fn_is_thread_id_valid */
142         },
143         {
144         "cortex_r4",                            /* target_name */
145         4,                                                      /* pointer_width; */
146         8,                                                      /* thread_stack_offset; */
147         40,                                                     /* thread_name_offset; */
148         48,                                                     /* thread_state_offset; */
149         136,                                            /* thread_next_offset */
150         &rtos_standard_cortex_r4_stacking,      /* stacking_info */
151         1,                                                      /* stacking_info_nb */
152         NULL,                                           /* fn_get_stacking_info */
153         NULL,                                           /* fn_is_thread_id_valid */
154         },
155         {
156         "arm926ejs",                            /* target_name */
157         4,                                                      /* pointer_width; */
158         8,                                                      /* thread_stack_offset; */
159         40,                                                     /* thread_name_offset; */
160         48,                                                     /* thread_state_offset; */
161         136,                                            /* thread_next_offset */
162         rtos_threadx_arm926ejs_stacking,        /* stacking_info */
163         2,                                                                      /* stacking_info_nb */
164         get_stacking_info_arm926ejs,            /* fn_get_stacking_info */
165         is_thread_id_valid_arm926ejs,           /* fn_is_thread_id_valid */
166         },
167         {
168         "hla_target",                           /* target_name */
169         4,                                                      /* pointer_width; */
170         8,                                                      /* thread_stack_offset; */
171         40,                                                     /* thread_name_offset; */
172         48,                                                     /* thread_state_offset; */
173         136,                                            /* thread_next_offset */
174         &rtos_standard_cortex_m3_stacking,      /* stacking_info */
175         1,                                                      /* stacking_info_nb */
176         NULL,                                           /* fn_get_stacking_info */
177         NULL,                                           /* fn_is_thread_id_valid */
178         },
179 };
180
181 enum threadx_symbol_values {
182         THREADX_VAL_TX_THREAD_CURRENT_PTR = 0,
183         THREADX_VAL_TX_THREAD_CREATED_PTR = 1,
184         THREADX_VAL_TX_THREAD_CREATED_COUNT = 2,
185 };
186
187 static const char * const threadx_symbol_list[] = {
188         "_tx_thread_current_ptr",
189         "_tx_thread_created_ptr",
190         "_tx_thread_created_count",
191         NULL
192 };
193
194 const struct rtos_type threadx_rtos = {
195         .name = "ThreadX",
196
197         .detect_rtos = threadx_detect_rtos,
198         .create = threadx_create,
199         .update_threads = threadx_update_threads,
200         .get_thread_reg_list = threadx_get_thread_reg_list,
201         .get_symbol_list_to_lookup = threadx_get_symbol_list_to_lookup,
202 };
203
204 static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
205 {
206         const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
207
208         if (param->fn_get_stacking_info)
209                 return param->fn_get_stacking_info(rtos, stack_ptr);
210
211         return param->stacking_info + 0;
212 }
213
214 static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
215 {
216         const struct threadx_params *param;
217
218         if (!rtos->rtos_specific_params)
219                 return 0; /* invalid */
220
221         param = (const struct threadx_params *) rtos->rtos_specific_params;
222
223         if (param->fn_is_thread_id_valid)
224                 return param->fn_is_thread_id_valid(rtos, thread_id);
225
226         return (thread_id != 0);
227 }
228
229 static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
230 {
231         const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
232         int     retval;
233         uint32_t flag;
234
235         retval = target_read_buffer(rtos->target,
236                         stack_ptr,
237                         sizeof(flag),
238                         (uint8_t *)&flag);
239         if (retval != ERROR_OK) {
240                 LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
241                 return NULL;
242         }
243
244         if (flag == 0) {
245                 LOG_DEBUG("  solicited stack");
246                 return param->stacking_info + 0;
247         } else {
248                 LOG_DEBUG("  interrupt stack: %" PRIu32, flag);
249                 return param->stacking_info + 1;
250         }
251 }
252
253 static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
254 {
255         return (thread_id != 0 && thread_id != 1);
256 }
257
258 static int threadx_update_threads(struct rtos *rtos)
259 {
260         int retval;
261         int tasks_found = 0;
262         int thread_list_size = 0;
263         const struct threadx_params *param;
264
265         if (!rtos)
266                 return -1;
267
268         if (!rtos->rtos_specific_params)
269                 return -3;
270
271         param = (const struct threadx_params *) rtos->rtos_specific_params;
272
273         if (!rtos->symbols) {
274                 LOG_ERROR("No symbols for ThreadX");
275                 return -4;
276         }
277
278         if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) {
279                 LOG_ERROR("Don't have the number of threads in ThreadX");
280                 return -2;
281         }
282
283         /* read the number of threads */
284         retval = target_read_buffer(rtos->target,
285                         rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address,
286                         4,
287                         (uint8_t *)&thread_list_size);
288
289         if (retval != ERROR_OK) {
290                 LOG_ERROR("Could not read ThreadX thread count from target");
291                 return retval;
292         }
293
294         /* wipe out previous thread details if any */
295         rtos_free_threadlist(rtos);
296
297         /* read the current thread id */
298         retval = target_read_buffer(rtos->target,
299                         rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address,
300                         4,
301                         (uint8_t *)&rtos->current_thread);
302
303         if (retval != ERROR_OK) {
304                 LOG_ERROR("Could not read ThreadX current thread from target");
305                 return retval;
306         }
307
308         if ((thread_list_size  == 0) || (rtos->current_thread == 0)) {
309                 /* Either : No RTOS threads - there is always at least the current execution though */
310                 /* OR     : No current thread - all threads suspended - show the current execution
311                  * of idling */
312                 char tmp_str[] = "Current Execution";
313                 thread_list_size++;
314                 tasks_found++;
315                 rtos->thread_details = malloc(
316                                 sizeof(struct thread_detail) * thread_list_size);
317                 rtos->thread_details->threadid = 1;
318                 rtos->thread_details->exists = true;
319                 rtos->thread_details->extra_info_str = NULL;
320                 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
321                 strcpy(rtos->thread_details->thread_name_str, tmp_str);
322
323                 if (thread_list_size == 0) {
324                         rtos->thread_count = 1;
325                         return ERROR_OK;
326                 }
327         } else {
328                 /* create space for new thread details */
329                 rtos->thread_details = malloc(
330                                 sizeof(struct thread_detail) * thread_list_size);
331         }
332
333         /* Read the pointer to the first thread */
334         int64_t thread_ptr = 0;
335         retval = target_read_buffer(rtos->target,
336                         rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address,
337                         param->pointer_width,
338                         (uint8_t *)&thread_ptr);
339         if (retval != ERROR_OK) {
340                 LOG_ERROR("Could not read ThreadX thread location from target");
341                 return retval;
342         }
343
344         /* loop over all threads */
345         int64_t prev_thread_ptr = 0;
346         while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
347
348                 #define THREADX_THREAD_NAME_STR_SIZE (200)
349                 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
350                 unsigned int i = 0;
351                 int64_t name_ptr = 0;
352
353                 /* Save the thread pointer */
354                 rtos->thread_details[tasks_found].threadid = thread_ptr;
355
356                 /* read the name pointer */
357                 retval = target_read_buffer(rtos->target,
358                                 thread_ptr + param->thread_name_offset,
359                                 param->pointer_width,
360                                 (uint8_t *)&name_ptr);
361                 if (retval != ERROR_OK) {
362                         LOG_ERROR("Could not read ThreadX thread name pointer from target");
363                         return retval;
364                 }
365
366                 /* Read the thread name */
367                 retval =
368                         target_read_buffer(rtos->target,
369                                 name_ptr,
370                                 THREADX_THREAD_NAME_STR_SIZE,
371                                 (uint8_t *)&tmp_str);
372                 if (retval != ERROR_OK) {
373                         LOG_ERROR("Error reading thread name from ThreadX target");
374                         return retval;
375                 }
376                 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
377
378                 if (tmp_str[0] == '\x00')
379                         strcpy(tmp_str, "No Name");
380
381                 rtos->thread_details[tasks_found].thread_name_str =
382                         malloc(strlen(tmp_str)+1);
383                 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
384
385                 /* Read the thread status */
386                 int64_t thread_status = 0;
387                 retval = target_read_buffer(rtos->target,
388                                 thread_ptr + param->thread_state_offset,
389                                 4,
390                                 (uint8_t *)&thread_status);
391                 if (retval != ERROR_OK) {
392                         LOG_ERROR("Error reading thread state from ThreadX target");
393                         return retval;
394                 }
395
396                 for (i = 0; (i < THREADX_NUM_STATES) &&
397                                 (threadx_thread_states[i].value != thread_status); i++) {
398                         /* empty */
399                 }
400
401                 const char *state_desc;
402                 if  (i < THREADX_NUM_STATES)
403                         state_desc = threadx_thread_states[i].desc;
404                 else
405                         state_desc = "Unknown state";
406
407                 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
408                                         state_desc)+8);
409                 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
410
411                 rtos->thread_details[tasks_found].exists = true;
412
413                 tasks_found++;
414                 prev_thread_ptr = thread_ptr;
415
416                 /* Get the location of the next thread structure. */
417                 thread_ptr = 0;
418                 retval = target_read_buffer(rtos->target,
419                                 prev_thread_ptr + param->thread_next_offset,
420                                 param->pointer_width,
421                                 (uint8_t *) &thread_ptr);
422                 if (retval != ERROR_OK) {
423                         LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
424                         return retval;
425                 }
426         }
427
428         rtos->thread_count = tasks_found;
429
430         return 0;
431 }
432
433 static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
434                 struct rtos_reg **reg_list, int *num_regs)
435 {
436         int retval;
437         const struct threadx_params *param;
438
439         if (!rtos)
440                 return -1;
441
442         if (!is_thread_id_valid(rtos, thread_id))
443                 return -2;
444
445         if (!rtos->rtos_specific_params)
446                 return -3;
447
448         param = (const struct threadx_params *) rtos->rtos_specific_params;
449
450         /* Read the stack pointer */
451         int64_t stack_ptr = 0;
452         retval = target_read_buffer(rtos->target,
453                         thread_id + param->thread_stack_offset,
454                         param->pointer_width,
455                         (uint8_t *)&stack_ptr);
456         if (retval != ERROR_OK) {
457                 LOG_ERROR("Error reading stack frame from ThreadX thread");
458                 return retval;
459         }
460
461         LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
462
463         if (stack_ptr == 0) {
464                 LOG_ERROR("null stack pointer in thread");
465                 return -5;
466         }
467
468         const struct rtos_register_stacking *stacking_info =
469                         get_stacking_info(rtos, stack_ptr);
470
471         if (!stacking_info) {
472                 LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
473                 return -6;
474         }
475
476         return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
477 }
478
479 static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
480 {
481         unsigned int i;
482         *symbol_list = calloc(
483                         ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem));
484
485         for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++)
486                 (*symbol_list)[i].symbol_name = threadx_symbol_list[i];
487
488         return 0;
489 }
490
491 static bool threadx_detect_rtos(struct target *target)
492 {
493         if ((target->rtos->symbols) &&
494                         (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) {
495                 /* looks like ThreadX */
496                 return true;
497         }
498         return false;
499 }
500
501 #if 0
502
503 static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id)
504 {
505         return 0;
506 }
507
508 static int threadx_get_thread_detail(struct rtos *rtos,
509         threadid_t thread_id,
510         struct thread_detail *detail)
511 {
512         unsigned int i = 0;
513         int retval;
514
515 #define THREADX_THREAD_NAME_STR_SIZE (200)
516         char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
517
518         const struct threadx_params *param;
519
520         if (!rtos)
521                 return -1;
522
523         if (thread_id == 0)
524                 return -2;
525
526         if (!rtos->rtos_specific_params)
527                 return -3;
528
529         param = (const struct threadx_params *) rtos->rtos_specific_params;
530
531         if (!rtos->symbols) {
532                 LOG_ERROR("No symbols for ThreadX");
533                 return -3;
534         }
535
536         detail->threadid = thread_id;
537
538         int64_t name_ptr = 0;
539         /* read the name pointer */
540         retval = target_read_buffer(rtos->target,
541                         thread_id + param->thread_name_offset,
542                         param->pointer_width,
543                         (uint8_t *)&name_ptr);
544         if (retval != ERROR_OK) {
545                 LOG_ERROR("Could not read ThreadX thread name pointer from target");
546                 return retval;
547         }
548
549         /* Read the thread name */
550         retval = target_read_buffer(rtos->target,
551                         name_ptr,
552                         THREADX_THREAD_NAME_STR_SIZE,
553                         (uint8_t *)&tmp_str);
554         if (retval != ERROR_OK) {
555                 LOG_ERROR("Error reading thread name from ThreadX target");
556                 return retval;
557         }
558         tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
559
560         if (tmp_str[0] == '\x00')
561                 strcpy(tmp_str, "No Name");
562
563         detail->thread_name_str = malloc(strlen(tmp_str)+1);
564
565         /* Read the thread status */
566         int64_t thread_status = 0;
567         retval =
568                 target_read_buffer(rtos->target,
569                         thread_id + param->thread_state_offset,
570                         4,
571                         (uint8_t *)&thread_status);
572         if (retval != ERROR_OK) {
573                 LOG_ERROR("Error reading thread state from ThreadX target");
574                 return retval;
575         }
576
577         for (i = 0; (i < THREADX_NUM_STATES) &&
578                         (threadx_thread_states[i].value != thread_status); i++) {
579                 /* empty */
580         }
581
582         char *state_desc;
583         if  (i < THREADX_NUM_STATES)
584                 state_desc = threadx_thread_states[i].desc;
585         else
586                 state_desc = "Unknown state";
587
588         detail->extra_info_str = malloc(strlen(state_desc)+1);
589
590         detail->exists = true;
591
592         return 0;
593 }
594
595 #endif
596
597 static int threadx_create(struct target *target)
598 {
599         for (unsigned int i = 0; i < ARRAY_SIZE(threadx_params_list); i++)
600                 if (strcmp(threadx_params_list[i].target_name, target->type->name) == 0) {
601                         target->rtos->rtos_specific_params = (void *)&threadx_params_list[i];
602                         target->rtos->current_thread = 0;
603                         target->rtos->thread_details = NULL;
604                         return 0;
605                 }
606
607         LOG_ERROR("Could not find target in ThreadX compatibility list");
608         return -1;
609 }