]> git.sur5r.net Git - openocd/blob - src/rtos/embKernel.c
update files to correct FSF address
[openocd] / src / rtos / embKernel.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  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "helper/types.h"
32 #include "rtos_embkernel_stackings.h"
33
34 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
35
36 static int embKernel_detect_rtos(struct target *target);
37 static int embKernel_create(struct target *target);
38 static int embKernel_update_threads(struct rtos *rtos);
39 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
40 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
41
42 struct rtos_type embKernel_rtos = {
43                 .name = "embKernel",
44                 .detect_rtos = embKernel_detect_rtos,
45                 .create = embKernel_create,
46                 .update_threads = embKernel_update_threads,
47                 .get_thread_reg_list =
48                 embKernel_get_thread_reg_list,
49                 .get_symbol_list_to_lookup = embKernel_get_symbol_list_to_lookup,
50 };
51
52 enum {
53         SYMBOL_ID_sCurrentTask = 0,
54         SYMBOL_ID_sListReady = 1,
55         SYMBOL_ID_sListSleep = 2,
56         SYMBOL_ID_sListSuspended = 3,
57         SYMBOL_ID_sMaxPriorities = 4,
58         SYMBOL_ID_sCurrentTaskCount = 5,
59 };
60
61 static char *embKernel_symbol_list[] = {
62                 "Rtos::sCurrentTask",
63                 "Rtos::sListReady",
64                 "Rtos::sListSleep",
65                 "Rtos::sListSuspended",
66                 "Rtos::sMaxPriorities",
67                 "Rtos::sCurrentTaskCount",
68                 NULL };
69
70 struct embKernel_params {
71         const char *target_name;
72         const unsigned char pointer_width;
73         const unsigned char thread_count_width;
74         const unsigned char rtos_list_size;
75         const unsigned char thread_stack_offset;
76         const unsigned char thread_name_offset;
77         const unsigned char thread_priority_offset;
78         const unsigned char thread_priority_width;
79         const unsigned char iterable_next_offset;
80         const unsigned char iterable_task_owner_offset;
81         const struct rtos_register_stacking *stacking_info;
82 };
83
84 struct embKernel_params embKernel_params_list[] = {
85                 {
86                         "cortex_m3", /* target_name */
87                         4, /* pointer_width */
88                         4, /* thread_count_width */
89                         8, /*rtos_list_size */
90                         0, /*thread_stack_offset */
91                         4, /*thread_name_offset */
92                         8, /*thread_priority_offset */
93                         4, /*thread_priority_width */
94                         4, /*iterable_next_offset */
95                         12, /*iterable_task_owner_offset */
96                         &rtos_embkernel_Cortex_M3_stacking, /* stacking_info*/
97                 },
98                 { "hla_target", /* target_name */
99                         4, /* pointer_width */
100                         4, /* thread_count_width */
101                         8, /*rtos_list_size */
102                         0, /*thread_stack_offset */
103                         4, /*thread_name_offset */
104                         8, /*thread_priority_offset */
105                         4, /*thread_priority_width */
106                         4, /*iterable_next_offset */
107                         12, /*iterable_task_owner_offset */
108                         &rtos_embkernel_Cortex_M3_stacking, /* stacking_info */
109                 }
110 };
111
112 static int embKernel_detect_rtos(struct target *target)
113 {
114         if (target->rtos->symbols != NULL) {
115                 if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0)
116                         return 1;
117         }
118         return 0;
119 }
120
121 static int embKernel_create(struct target *target)
122 {
123         size_t i = 0;
124         while ((i < ARRAY_SIZE(embKernel_params_list)) &&
125                         (0 != strcmp(embKernel_params_list[i].target_name, target->type->name)))
126                 i++;
127
128         if (i >= ARRAY_SIZE(embKernel_params_list)) {
129                 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
130                                 "list", target->type->name);
131                 return -1;
132         }
133
134         target->rtos->rtos_specific_params = (void *) &embKernel_params_list[i];
135         return 0;
136 }
137
138 static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
139                 struct thread_detail *details, const char* state_str)
140 {
141         int64_t task = 0;
142         int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
143                         (uint8_t *) &task);
144         if (retval != ERROR_OK)
145                 return retval;
146         details->threadid = (threadid_t) task;
147         details->exists = true;
148         details->display_str = NULL;
149
150         int64_t name_ptr = 0;
151         retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
152                         (uint8_t *) &name_ptr);
153         if (retval != ERROR_OK)
154                 return retval;
155
156         details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
157         if (name_ptr) {
158                 retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
159                                 (uint8_t *) details->thread_name_str);
160                 if (retval != ERROR_OK)
161                         return retval;
162                 details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
163         } else {
164                 snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
165         }
166
167         int64_t priority = 0;
168         retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
169                         (uint8_t *) &priority);
170         if (retval != ERROR_OK)
171                 return retval;
172         details->extra_info_str = (char *) malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
173         if (task == rtos->current_thread) {
174                 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running",
175                                 (unsigned int) priority);
176         } else {
177                 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority,
178                                 state_str);
179         }
180
181         LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
182                         (unsigned int)task, details->thread_name_str);
183         return 0;
184 }
185
186 static int embKernel_update_threads(struct rtos *rtos)
187 {
188         /* int i = 0; */
189         int retval;
190         const struct embKernel_params *param;
191
192         if (rtos == NULL)
193                 return -1;
194
195         if (rtos->rtos_specific_params == NULL)
196                 return -3;
197
198         if (rtos->symbols == NULL) {
199                 LOG_ERROR("No symbols for embKernel");
200                 return -4;
201         }
202
203         if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) {
204                 LOG_ERROR("Don't have the thread list head");
205                 return -2;
206         }
207
208         /* wipe out previous thread details if any */
209         if (rtos->thread_details != NULL) {
210                 int j;
211                 for (j = 0; j < rtos->thread_count; j++) {
212                         if (rtos->thread_details[j].display_str != NULL) {
213                                 free(rtos->thread_details[j].display_str);
214                                 rtos->thread_details[j].display_str = NULL;
215                         }
216                         if (rtos->thread_details[j].thread_name_str != NULL) {
217                                 free(rtos->thread_details[j].thread_name_str);
218                                 rtos->thread_details[j].thread_name_str = NULL;
219                         }
220                         if (rtos->thread_details[j].extra_info_str != NULL) {
221                                 free(rtos->thread_details[j].extra_info_str);
222                                 rtos->thread_details[j].extra_info_str = NULL;
223                         }
224                 }
225                 free(rtos->thread_details);
226                 rtos->thread_details = NULL;
227         }
228
229         param = (const struct embKernel_params *) rtos->rtos_specific_params;
230
231         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
232                         (uint8_t *) &rtos->current_thread);
233         if (retval != ERROR_OK) {
234                 LOG_ERROR("Error reading current thread in embKernel thread list");
235                 return retval;
236         }
237
238         int64_t max_used_priority = 0;
239         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
240                         (uint8_t *) &max_used_priority);
241         if (retval != ERROR_OK)
242                 return retval;
243
244         int thread_list_size = 0;
245         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
246                         param->thread_count_width, (uint8_t *) &thread_list_size);
247
248         if (retval != ERROR_OK) {
249                 LOG_ERROR("Could not read embKernel thread count from target");
250                 return retval;
251         }
252
253         /* create space for new thread details */
254         rtos->thread_details = (struct thread_detail *) malloc(sizeof(struct thread_detail) * thread_list_size);
255         if (!rtos->thread_details) {
256                 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
257                 return ERROR_FAIL;
258         }
259
260         int threadIdx = 0;
261         /* Look for ready tasks */
262         for (int pri = 0; pri < max_used_priority; pri++) {
263                 /* Get first item in queue */
264                 int64_t iterable = 0;
265                 retval = target_read_buffer(rtos->target,
266                                 rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
267                                 (uint8_t *) &iterable);
268                 if (retval != ERROR_OK)
269                         return retval;
270                 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
271                         /* Get info from this iterable item */
272                         retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
273                         if (retval != ERROR_OK)
274                                 return retval;
275                         /* Get next iterable item */
276                         retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
277                                         (uint8_t *) &iterable);
278                         if (retval != ERROR_OK)
279                                 return retval;
280                 }
281         }
282         /* Look for sleeping tasks */
283         int64_t iterable = 0;
284         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width,
285                         (uint8_t *) &iterable);
286         if (retval != ERROR_OK)
287                 return retval;
288         for (; iterable && threadIdx < thread_list_size; threadIdx++) {
289                 /*Get info from this iterable item */
290                 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping");
291                 if (retval != ERROR_OK)
292                         return retval;
293                 /*Get next iterable item */
294                 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
295                                 (uint8_t *) &iterable);
296                 if (retval != ERROR_OK)
297                         return retval;
298         }
299
300         /* Look for suspended tasks  */
301         iterable = 0;
302         retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width,
303                         (uint8_t *) &iterable);
304         if (retval != ERROR_OK)
305                 return retval;
306         for (; iterable && threadIdx < thread_list_size; threadIdx++) {
307                 /* Get info from this iterable item */
308                 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended");
309                 if (retval != ERROR_OK)
310                         return retval;
311                 /*Get next iterable item */
312                 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
313                                 (uint8_t *) &iterable);
314                 if (retval != ERROR_OK)
315                         return retval;
316         }
317
318         rtos->thread_count = 0;
319         rtos->thread_count = threadIdx;
320         LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
321         return 0;
322 }
323
324 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
325 {
326         int retval;
327         const struct embKernel_params *param;
328         int64_t stack_ptr = 0;
329
330         *hex_reg_list = NULL;
331         if (rtos == NULL)
332                 return -1;
333
334         if (thread_id == 0)
335                 return -2;
336
337         if (rtos->rtos_specific_params == NULL)
338                 return -1;
339
340         param = (const struct embKernel_params *) rtos->rtos_specific_params;
341
342         /* Read the stack pointer */
343         retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
344                         (uint8_t *) &stack_ptr);
345         if (retval != ERROR_OK) {
346                 LOG_ERROR("Error reading stack frame from embKernel thread");
347                 return retval;
348         }
349
350         return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
351 }
352
353 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
354 {
355         unsigned int i;
356         *symbol_list = (symbol_table_elem_t *) malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(embKernel_symbol_list));
357
358         for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
359                 (*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
360
361         return 0;
362 }
363