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