a9e313bf2ef44bbe1ae2c4ca6ed45c6d086e07f0
[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, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "rtos_standard_stackings.h"
32
33 static int ThreadX_detect_rtos(struct target *target);
34 static int ThreadX_create(struct target *target);
35 static int ThreadX_update_threads(struct rtos *rtos);
36 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
37 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
38
39 struct ThreadX_thread_state {
40         int value;
41         char *desc;
42 };
43
44 struct ThreadX_thread_state ThreadX_thread_states[] = {
45         { 0,  "Ready" },
46         { 1,  "Completed" },
47         { 2,  "Terminated" },
48         { 3,  "Suspended" },
49         { 4,  "Sleeping" },
50         { 5,  "Waiting - Queue" },
51         { 6,  "Waiting - Semaphore" },
52         { 7,  "Waiting - Event flag" },
53         { 8,  "Waiting - Memory" },
54         { 9,  "Waiting - Memory" },
55         { 10, "Waiting - I/O" },
56         { 11, "Waiting - Filesystem" },
57         { 12, "Waiting - Network" },
58         { 13, "Waiting - Mutex" },
59 };
60
61 #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state))
62
63 struct ThreadX_params {
64         char *target_name;
65         unsigned char pointer_width;
66         unsigned char thread_stack_offset;
67         unsigned char thread_name_offset;
68         unsigned char thread_state_offset;
69         unsigned char thread_next_offset;
70         const struct rtos_register_stacking *stacking_info;
71 };
72
73 const struct ThreadX_params ThreadX_params_list[] = {
74         {
75         "cortex_m3",                            /* target_name */
76         4,                                                      /* pointer_width; */
77         8,                                                      /* thread_stack_offset; */
78         40,                                                     /* thread_name_offset; */
79         48,                                                     /* thread_state_offset; */
80         136,                                            /* thread_next_offset */
81         &rtos_standard_Cortex_M3_stacking,      /* stacking_info */
82         }
83 };
84
85 #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params)))
86
87 enum ThreadX_symbol_values {
88         ThreadX_VAL_tx_thread_current_ptr = 0,
89         ThreadX_VAL_tx_thread_created_ptr = 1,
90         ThreadX_VAL_tx_thread_created_count = 2,
91 };
92
93 static char *ThreadX_symbol_list[] = {
94         "_tx_thread_current_ptr",
95         "_tx_thread_created_ptr",
96         "_tx_thread_created_count",
97         NULL
98 };
99
100 #define THREADX_NUM_SYMBOLS (sizeof(ThreadX_symbol_list)/sizeof(char *))
101
102 const struct rtos_type ThreadX_rtos = {
103         .name = "ThreadX",
104
105         .detect_rtos = ThreadX_detect_rtos,
106         .create = ThreadX_create,
107         .update_threads = ThreadX_update_threads,
108         .get_thread_reg_list = ThreadX_get_thread_reg_list,
109         .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup,
110
111 };
112
113 static int ThreadX_update_threads(struct rtos *rtos)
114 {
115         int retval;
116         int tasks_found = 0;
117         int thread_list_size = 0;
118         const struct ThreadX_params *param;
119
120         if (rtos == NULL)
121                 return -1;
122
123         if (rtos->rtos_specific_params == NULL)
124                 return -3;
125
126         param = (const struct ThreadX_params *) rtos->rtos_specific_params;
127
128         if (rtos->symbols == NULL) {
129                 LOG_OUTPUT("No symbols for ThreadX\r\n");
130                 return -4;
131         }
132
133         if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) {
134                 LOG_OUTPUT("Don't have the number of threads in ThreadX \r\n");
135                 return -2;
136         }
137
138         /* read the number of threads */
139         retval = target_read_buffer(rtos->target,
140                         rtos->symbols[ThreadX_VAL_tx_thread_created_count].address,
141                         4,
142                         (uint8_t *)&thread_list_size);
143
144         if (retval != ERROR_OK) {
145                 LOG_OUTPUT("Could not read ThreadX thread count from target\r\n");
146                 return retval;
147         }
148
149         /* wipe out previous thread details if any */
150         if (rtos->thread_details != NULL) {
151                 int j;
152                 for (j = 0; j < rtos->thread_count; j++) {
153                         if (rtos->thread_details[j].display_str != NULL) {
154                                 free(rtos->thread_details[j].display_str);
155                                 rtos->thread_details[j].display_str = NULL;
156                         }
157                         if (rtos->thread_details[j].thread_name_str != NULL) {
158                                 free(rtos->thread_details[j].thread_name_str);
159                                 rtos->thread_details[j].thread_name_str = NULL;
160                         }
161                         if (rtos->thread_details[j].extra_info_str != NULL) {
162                                 free(rtos->thread_details[j].extra_info_str);
163                                 rtos->thread_details[j].extra_info_str = NULL;
164                         }
165                 }
166                 free(rtos->thread_details);
167                 rtos->thread_details = NULL;
168         }
169
170         /* read the current thread id */
171         retval = target_read_buffer(rtos->target,
172                         rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address,
173                         4,
174                         (uint8_t *)&rtos->current_thread);
175
176         if (retval != ERROR_OK) {
177                 LOG_OUTPUT("Could not read ThreadX current thread from target\r\n");
178                 return retval;
179         }
180
181         if ((thread_list_size  == 0) || (rtos->current_thread == 0)) {
182                 /* Either : No RTOS threads - there is always at least the current execution though */
183                 /* OR     : No current thread - all threads suspended - show the current execution
184                  * of idling */
185                 char tmp_str[] = "Current Execution";
186                 thread_list_size++;
187                 tasks_found++;
188                 rtos->thread_details = (struct thread_detail *) malloc(
189                                 sizeof(struct thread_detail) * thread_list_size);
190                 rtos->thread_details->threadid = 1;
191                 rtos->thread_details->exists = true;
192                 rtos->thread_details->display_str = NULL;
193                 rtos->thread_details->extra_info_str = NULL;
194                 rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str));
195                 strcpy(rtos->thread_details->thread_name_str, tmp_str);
196
197                 if (thread_list_size == 0) {
198                         rtos->thread_count = 1;
199                         return ERROR_OK;
200                 }
201         } else {
202                 /* create space for new thread details */
203                 rtos->thread_details = (struct thread_detail *) malloc(
204                                 sizeof(struct thread_detail) * thread_list_size);
205         }
206
207         /* Read the pointer to the first thread */
208         int64_t thread_ptr = 0;
209         retval = target_read_buffer(rtos->target,
210                         rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address,
211                         param->pointer_width,
212                         (uint8_t *)&thread_ptr);
213         if (retval != ERROR_OK) {
214                 LOG_OUTPUT("Could not read ThreadX thread location from target\r\n");
215                 return retval;
216         }
217
218         /* loop over all threads */
219         int64_t prev_thread_ptr = 0;
220         while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
221
222                 #define THREADX_THREAD_NAME_STR_SIZE (200)
223                 char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
224                 unsigned int i = 0;
225                 int64_t name_ptr = 0;
226
227                 /* Save the thread pointer */
228                 rtos->thread_details[tasks_found].threadid = thread_ptr;
229
230                 /* read the name pointer */
231                 retval = target_read_buffer(rtos->target,
232                                 thread_ptr + param->thread_name_offset,
233                                 param->pointer_width,
234                                 (uint8_t *)&name_ptr);
235                 if (retval != ERROR_OK) {
236                         LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n");
237                         return retval;
238                 }
239
240                 /* Read the thread name */
241                 retval =
242                         target_read_buffer(rtos->target,
243                                 name_ptr,
244                                 THREADX_THREAD_NAME_STR_SIZE,
245                                 (uint8_t *)&tmp_str);
246                 if (retval != ERROR_OK) {
247                         LOG_OUTPUT("Error reading thread name from ThreadX target\r\n");
248                         return retval;
249                 }
250                 tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
251
252                 if (tmp_str[0] == '\x00')
253                         strcpy(tmp_str, "No Name");
254
255                 rtos->thread_details[tasks_found].thread_name_str =
256                         (char *)malloc(strlen(tmp_str)+1);
257                 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
258
259                 /* Read the thread status */
260                 int64_t thread_status = 0;
261                 retval = target_read_buffer(rtos->target,
262                                 thread_ptr + param->thread_state_offset,
263                                 4,
264                                 (uint8_t *)&thread_status);
265                 if (retval != ERROR_OK) {
266                         LOG_OUTPUT("Error reading thread state from ThreadX target\r\n");
267                         return retval;
268                 }
269
270                 for (i = 0; (i < THREADX_NUM_STATES) &&
271                                 (ThreadX_thread_states[i].value != thread_status); i++) {
272                         /* empty */
273                 }
274
275                 char *state_desc;
276                 if  (i < THREADX_NUM_STATES)
277                         state_desc = ThreadX_thread_states[i].desc;
278                 else
279                         state_desc = "Unknown state";
280
281                 rtos->thread_details[tasks_found].extra_info_str = (char *)malloc(strlen(
282                                         state_desc)+1);
283                 strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
284
285                 rtos->thread_details[tasks_found].exists = true;
286
287                 rtos->thread_details[tasks_found].display_str = NULL;
288
289                 tasks_found++;
290                 prev_thread_ptr = thread_ptr;
291
292                 /* Get the location of the next thread structure. */
293                 thread_ptr = 0;
294                 retval = target_read_buffer(rtos->target,
295                                 prev_thread_ptr + param->thread_next_offset,
296                                 param->pointer_width,
297                                 (uint8_t *) &thread_ptr);
298                 if (retval != ERROR_OK) {
299                         LOG_OUTPUT("Error reading next thread pointer in ThreadX thread list\r\n");
300                         return retval;
301                 }
302         }
303
304         rtos->thread_count = tasks_found;
305
306         return 0;
307 }
308
309 static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
310 {
311         int retval;
312         const struct ThreadX_params *param;
313
314         *hex_reg_list = NULL;
315
316         if (rtos == NULL)
317                 return -1;
318
319         if (thread_id == 0)
320                 return -2;
321
322         if (rtos->rtos_specific_params == NULL)
323                 return -3;
324
325         param = (const struct ThreadX_params *) rtos->rtos_specific_params;
326
327         /* Read the stack pointer */
328         int64_t stack_ptr = 0;
329         retval = target_read_buffer(rtos->target,
330                         thread_id + param->thread_stack_offset,
331                         param->pointer_width,
332                         (uint8_t *)&stack_ptr);
333         if (retval != ERROR_OK) {
334                 LOG_OUTPUT("Error reading stack frame from ThreadX thread\r\n");
335                 return retval;
336         }
337
338         return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
339 }
340
341 static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
342 {
343         unsigned int i;
344         *symbol_list = (symbol_table_elem_t *) malloc(
345                         sizeof(symbol_table_elem_t) * THREADX_NUM_SYMBOLS);
346
347         for (i = 0; i < THREADX_NUM_SYMBOLS; i++)
348                 (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
349
350         return 0;
351 }
352
353 static int ThreadX_detect_rtos(struct target *target)
354 {
355         if ((target->rtos->symbols != NULL) &&
356                         (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) {
357                 /* looks like ThreadX */
358                 return 1;
359         }
360         return 0;
361 }
362
363 #if 0
364
365 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id)
366 {
367         return 0;
368 }
369
370 static int ThreadX_get_thread_detail(struct rtos *rtos,
371         threadid_t thread_id,
372         struct thread_detail *detail)
373 {
374         unsigned int i = 0;
375         int retval;
376
377 #define THREADX_THREAD_NAME_STR_SIZE (200)
378         char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
379
380         const struct ThreadX_params *param;
381
382         if (rtos == NULL)
383                 return -1;
384
385         if (thread_id == 0)
386                 return -2;
387
388         if (rtos->rtos_specific_params == NULL)
389                 return -3;
390
391         param = (const struct ThreadX_params *) rtos->rtos_specific_params;
392
393         if (rtos->symbols == NULL) {
394                 LOG_OUTPUT("No symbols for ThreadX\r\n");
395                 return -3;
396         }
397
398         detail->threadid = thread_id;
399
400         int64_t name_ptr = 0;
401         /* read the name pointer */
402         retval = target_read_buffer(rtos->target,
403                         thread_id + param->thread_name_offset,
404                         param->pointer_width,
405                         (uint8_t *)&name_ptr);
406         if (retval != ERROR_OK) {
407                 LOG_OUTPUT("Could not read ThreadX thread name pointer from target\r\n");
408                 return retval;
409         }
410
411         /* Read the thread name */
412         retval = target_read_buffer(rtos->target,
413                         name_ptr,
414                         THREADX_THREAD_NAME_STR_SIZE,
415                         (uint8_t *)&tmp_str);
416         if (retval != ERROR_OK) {
417                 LOG_OUTPUT("Error reading thread name from ThreadX target\r\n");
418                 return retval;
419         }
420         tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
421
422         if (tmp_str[0] == '\x00')
423                 strcpy(tmp_str, "No Name");
424
425         detail->thread_name_str = (char *)malloc(strlen(tmp_str)+1);
426
427         /* Read the thread status */
428         int64_t thread_status = 0;
429         retval =
430                 target_read_buffer(rtos->target,
431                         thread_id + param->thread_state_offset,
432                         4,
433                         (uint8_t *)&thread_status);
434         if (retval != ERROR_OK) {
435                 LOG_OUTPUT("Error reading thread state from ThreadX target\r\n");
436                 return retval;
437         }
438
439         for (i = 0; (i < THREADX_NUM_STATES) &&
440                         (ThreadX_thread_states[i].value != thread_status); i++) {
441                 /* empty */
442         }
443
444         char *state_desc;
445         if  (i < THREADX_NUM_STATES)
446                 state_desc = ThreadX_thread_states[i].desc;
447         else
448                 state_desc = "Unknown state";
449
450         detail->extra_info_str = (char *)malloc(strlen(state_desc)+1);
451
452         detail->exists = true;
453
454         detail->display_str = NULL;
455
456         return 0;
457 }
458
459 #endif
460
461 static int ThreadX_create(struct target *target)
462 {
463         int i = 0;
464         while ((i < THREADX_NUM_PARAMS) &&
465                         (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) {
466                 i++;
467         }
468         if (i >= THREADX_NUM_PARAMS) {
469                 LOG_OUTPUT("Could not find target in ThreadX compatibility list\r\n");
470                 return -1;
471         }
472
473         target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i];
474         target->rtos->current_thread = 0;
475         target->rtos->thread_details = NULL;
476         return 0;
477 }