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