5c18916a12ee58908413bd4410f8ede84cb08d7c
[fw/openocd] / src / rtos / eCos.c
1 /***************************************************************************
2  *                                                                         *
3  *   This program is free software; you can redistribute it and/or modify  *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  *   This program is distributed in the hope that it will be useful,       *
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
11  *   GNU General Public License for more details.                          *
12  *                                                                         *
13  *   You should have received a copy of the GNU General Public License     *
14  *   along with this program; if not, write to the                         *
15  *   Free Software Foundation, Inc.,                                       *
16  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
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 "rtos_ecos_stackings.h"
30
31 static int eCos_detect_rtos(struct target *target);
32 static int eCos_create(struct target *target);
33 static int eCos_update_threads(struct rtos *rtos);
34 static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
35 static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
36
37 struct eCos_thread_state {
38         int value;
39         char *desc;
40 };
41
42 struct eCos_thread_state eCos_thread_states[] = {
43         { 0, "Ready" },
44         { 1, "Sleeping" },
45         { 2, "Countsleep" },
46         { 4, "Suspended" },
47         { 8, "Creating" },
48         { 16, "Exited" }
49 };
50
51 #define ECOS_NUM_STATES (sizeof(eCos_thread_states)/sizeof(struct eCos_thread_state))
52
53 struct eCos_params {
54         char *target_name;
55         unsigned char pointer_width;
56         unsigned char thread_stack_offset;
57         unsigned char thread_name_offset;
58         unsigned char thread_state_offset;
59         unsigned char thread_next_offset;
60         unsigned char thread_uniqueid_offset;
61         const struct rtos_register_stacking *stacking_info;
62 };
63
64 const struct eCos_params eCos_params_list[] = {
65         {
66         "cortex_m3",                    /* target_name */
67         4,                                              /* pointer_width; */
68         0x0c,                                   /* thread_stack_offset; */
69         0x9c,                                   /* thread_name_offset; */
70         0x3c,                                   /* thread_state_offset; */
71         0xa0,                                   /* thread_next_offset */
72         0x4c,                                   /* thread_uniqueid_offset */
73         &rtos_eCos_Cortex_M3_stacking   /* stacking_info */
74         }
75 };
76
77 #define ECOS_NUM_PARAMS ((int)(sizeof(eCos_params_list)/sizeof(struct eCos_params)))
78
79 enum eCos_symbol_values {
80         eCos_VAL_thread_list = 0,
81         eCos_VAL_current_thread_ptr = 1
82 };
83
84 static char *eCos_symbol_list[] = {
85         "Cyg_Thread::thread_list",
86         "Cyg_Scheduler_Base::current_thread",
87         NULL
88 };
89
90 #define ECOS_NUM_SYMBOLS (sizeof(eCos_symbol_list)/sizeof(char *))
91
92 const struct rtos_type eCos_rtos = {
93         .name = "eCos",
94
95         .detect_rtos = eCos_detect_rtos,
96         .create = eCos_create,
97         .update_threads = eCos_update_threads,
98         .get_thread_reg_list = eCos_get_thread_reg_list,
99         .get_symbol_list_to_lookup = eCos_get_symbol_list_to_lookup,
100
101 };
102
103 static int eCos_update_threads(struct rtos *rtos)
104 {
105         int retval;
106         int tasks_found = 0;
107         int thread_list_size = 0;
108         const struct eCos_params *param;
109
110         if (rtos == NULL)
111                 return -1;
112
113         if (rtos->rtos_specific_params == NULL)
114                 return -3;
115
116         param = (const struct eCos_params *) rtos->rtos_specific_params;
117
118         if (rtos->symbols == NULL) {
119                 LOG_OUTPUT("No symbols for eCos\r\n");
120                 return -4;
121         }
122
123         if (rtos->symbols[eCos_VAL_thread_list].address == 0) {
124                 LOG_OUTPUT("Don't have the thread list head\r\n");
125                 return -2;
126         }
127
128         /* wipe out previous thread details if any */
129         if (rtos->thread_details != NULL) {
130                 int j;
131                 for (j = 0; j < rtos->thread_count; j++) {
132                         if (rtos->thread_details[j].display_str != NULL) {
133                                 free(rtos->thread_details[j].display_str);
134                                 rtos->thread_details[j].display_str = NULL;
135                         }
136                         if (rtos->thread_details[j].thread_name_str != NULL) {
137                                 free(rtos->thread_details[j].thread_name_str);
138                                 rtos->thread_details[j].thread_name_str = NULL;
139                         }
140                         if (rtos->thread_details[j].extra_info_str != NULL) {
141                                 free(rtos->thread_details[j].extra_info_str);
142                                 rtos->thread_details[j].extra_info_str = NULL;
143                         }
144                 }
145                 free(rtos->thread_details);
146                 rtos->thread_details = NULL;
147         }
148
149         /* determine the number of current threads */
150         uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address;
151         uint32_t thread_index;
152         target_read_buffer(rtos->target,
153                 thread_list_head,
154                 param->pointer_width,
155                 (uint8_t *) &thread_index);
156         uint32_t first_thread = thread_index;
157         do {
158                 thread_list_size++;
159                 retval = target_read_buffer(rtos->target,
160                                 thread_index + param->thread_next_offset,
161                                 param->pointer_width,
162                                 (uint8_t *) &thread_index);
163                 if (retval != ERROR_OK)
164                         return retval;
165         } while (thread_index != first_thread);
166
167         /* read the current thread id */
168         uint32_t current_thread_addr;
169         retval = target_read_buffer(rtos->target,
170                         rtos->symbols[eCos_VAL_current_thread_ptr].address,
171                         4,
172                         (uint8_t *)&current_thread_addr);
173         if (retval != ERROR_OK)
174                 return retval;
175         rtos->current_thread = 0;
176         retval = target_read_buffer(rtos->target,
177                         current_thread_addr + param->thread_uniqueid_offset,
178                         2,
179                         (uint8_t *)&rtos->current_thread);
180         if (retval != ERROR_OK) {
181                 LOG_OUTPUT("Could not read eCos current thread from target\r\n");
182                 return retval;
183         }
184
185         if ((thread_list_size  == 0) || (rtos->current_thread == 0)) {
186                 /* Either : No RTOS threads - there is always at least the current execution though */
187                 /* OR     : No current thread - all threads suspended - show the current execution
188                  * of idling */
189                 char tmp_str[] = "Current Execution";
190                 thread_list_size++;
191                 tasks_found++;
192                 rtos->thread_details = (struct thread_detail *) malloc(
193                                 sizeof(struct thread_detail) * thread_list_size);
194                 rtos->thread_details->threadid = 1;
195                 rtos->thread_details->exists = true;
196                 rtos->thread_details->display_str = NULL;
197                 rtos->thread_details->extra_info_str = NULL;
198                 rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str));
199                 strcpy(rtos->thread_details->thread_name_str, tmp_str);
200
201                 if (thread_list_size == 0) {
202                         rtos->thread_count = 1;
203                         return ERROR_OK;
204                 }
205         } else {
206                 /* create space for new thread details */
207                 rtos->thread_details = (struct thread_detail *) malloc(
208                                 sizeof(struct thread_detail) * thread_list_size);
209         }
210
211         /* loop over all threads */
212         thread_index = first_thread;
213         do {
214
215                 #define ECOS_THREAD_NAME_STR_SIZE (200)
216                 char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
217                 unsigned int i = 0;
218                 uint32_t name_ptr = 0;
219                 uint32_t prev_thread_ptr;
220
221                 /* Save the thread pointer */
222                 uint16_t thread_id;
223                 retval = target_read_buffer(rtos->target,
224                                 thread_index + param->thread_uniqueid_offset,
225                                 2,
226                                 (uint8_t *)&thread_id);
227                 if (retval != ERROR_OK) {
228                         LOG_OUTPUT("Could not read eCos thread id from target\r\n");
229                         return retval;
230                 }
231                 rtos->thread_details[tasks_found].threadid = thread_id;
232
233                 /* read the name pointer */
234                 retval = target_read_buffer(rtos->target,
235                                 thread_index + param->thread_name_offset,
236                                 param->pointer_width,
237                                 (uint8_t *)&name_ptr);
238                 if (retval != ERROR_OK) {
239                         LOG_OUTPUT("Could not read eCos thread name pointer from target\r\n");
240                         return retval;
241                 }
242
243                 /* Read the thread name */
244                 retval =
245                         target_read_buffer(rtos->target,
246                                 name_ptr,
247                                 ECOS_THREAD_NAME_STR_SIZE,
248                                 (uint8_t *)&tmp_str);
249                 if (retval != ERROR_OK) {
250                         LOG_OUTPUT("Error reading thread name from eCos target\r\n");
251                         return retval;
252                 }
253                 tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
254
255                 if (tmp_str[0] == '\x00')
256                         strcpy(tmp_str, "No Name");
257
258                 rtos->thread_details[tasks_found].thread_name_str =
259                         (char *)malloc(strlen(tmp_str)+1);
260                 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
261
262                 /* Read the thread status */
263                 int64_t thread_status = 0;
264                 retval = target_read_buffer(rtos->target,
265                                 thread_index + param->thread_state_offset,
266                                 4,
267                                 (uint8_t *)&thread_status);
268                 if (retval != ERROR_OK) {
269                         LOG_OUTPUT("Error reading thread state from eCos target\r\n");
270                         return retval;
271                 }
272
273                 for (i = 0; (i < ECOS_NUM_STATES) && (eCos_thread_states[i].value != thread_status); i++) {
274                         /*
275                          * empty
276                          */
277                 }
278
279                 char *state_desc;
280                 if  (i < ECOS_NUM_STATES)
281                         state_desc = eCos_thread_states[i].desc;
282                 else
283                         state_desc = "Unknown state";
284
285                 rtos->thread_details[tasks_found].extra_info_str = (char *)malloc(strlen(
286                                         state_desc)+1);
287                 strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc);
288
289                 rtos->thread_details[tasks_found].exists = true;
290
291                 rtos->thread_details[tasks_found].display_str = NULL;
292
293                 tasks_found++;
294                 prev_thread_ptr = thread_index;
295
296                 /* Get the location of the next thread structure. */
297                 thread_index = rtos->symbols[eCos_VAL_thread_list].address;
298                 retval = target_read_buffer(rtos->target,
299                                 prev_thread_ptr + param->thread_next_offset,
300                                 param->pointer_width,
301                                 (uint8_t *) &thread_index);
302                 if (retval != ERROR_OK) {
303                         LOG_OUTPUT("Error reading next thread pointer in eCos thread list\r\n");
304                         return retval;
305                 }
306         } while (thread_index != first_thread);
307
308         rtos->thread_count = tasks_found;
309         return 0;
310 }
311
312 static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
313 {
314         int retval;
315         const struct eCos_params *param;
316
317         *hex_reg_list = NULL;
318
319         if (rtos == NULL)
320                 return -1;
321
322         if (thread_id == 0)
323                 return -2;
324
325         if (rtos->rtos_specific_params == NULL)
326                 return -3;
327
328         param = (const struct eCos_params *) rtos->rtos_specific_params;
329
330         /* Find the thread with that thread id */
331         uint16_t id = 0;
332         uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address;
333         uint32_t thread_index;
334         target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
335                         (uint8_t *)&thread_index);
336         bool done = false;
337         while (!done) {
338                 retval = target_read_buffer(rtos->target,
339                                 thread_index + param->thread_uniqueid_offset,
340                                 2,
341                                 (uint8_t *)&id);
342                 if (retval != ERROR_OK) {
343                         LOG_OUTPUT("Error reading unique id from eCos thread\r\n");
344                         return retval;
345                 }
346
347                 if (id == thread_id) {
348                         done = true;
349                         break;
350                 }
351                 target_read_buffer(rtos->target,
352                         thread_index + param->thread_next_offset,
353                         param->pointer_width,
354                         (uint8_t *) &thread_index);
355         }
356
357         if (done) {
358                 /* Read the stack pointer */
359                 int64_t stack_ptr = 0;
360                 retval = target_read_buffer(rtos->target,
361                                 thread_index + param->thread_stack_offset,
362                                 param->pointer_width,
363                                 (uint8_t *)&stack_ptr);
364                 if (retval != ERROR_OK) {
365                         LOG_OUTPUT("Error reading stack frame from eCos thread\r\n");
366                         return retval;
367                 }
368
369                 return rtos_generic_stack_read(rtos->target,
370                         param->stacking_info,
371                         stack_ptr,
372                         hex_reg_list);
373         }
374
375         return -1;
376 }
377
378 static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
379 {
380         unsigned int i;
381         *symbol_list = (symbol_table_elem_t *) malloc(
382                         sizeof(symbol_table_elem_t) * ECOS_NUM_SYMBOLS);
383
384         for (i = 0; i < ECOS_NUM_SYMBOLS; i++)
385                 (*symbol_list)[i].symbol_name = eCos_symbol_list[i];
386
387         return 0;
388 }
389
390 static int eCos_detect_rtos(struct target *target)
391 {
392         if ((target->rtos->symbols != NULL) &&
393                         (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) {
394                 /* looks like eCos */
395                 return 1;
396         }
397         return 0;
398 }
399
400 static int eCos_create(struct target *target)
401 {
402         int i = 0;
403         while ((i < ECOS_NUM_PARAMS) &&
404                 (0 != strcmp(eCos_params_list[i].target_name, target->type->name))) {
405                 i++;
406         }
407         if (i >= ECOS_NUM_PARAMS) {
408                 LOG_OUTPUT("Could not find target in eCos compatibility list\r\n");
409                 return -1;
410         }
411
412         target->rtos->rtos_specific_params = (void *) &eCos_params_list[i];
413         target->rtos->current_thread = 0;
414         target->rtos->thread_details = NULL;
415         return 0;
416 }