1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
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. *
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. *
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 ***************************************************************************/
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_embkernel_stackings.h"
34 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
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
[]);
42 struct rtos_type embKernel_rtos
= {
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
,
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,
61 static char *embKernel_symbol_list
[] = {
65 "Rtos::sListSuspended",
66 "Rtos::sMaxPriorities",
67 "Rtos::sCurrentTaskCount",
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
;
84 struct embKernel_params embKernel_params_list
[] = {
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*/
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 */
112 static int embKernel_detect_rtos(struct target
*target
)
114 if (target
->rtos
->symbols
!= NULL
) {
115 if (target
->rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
!= 0)
121 static int embKernel_create(struct target
*target
)
124 while ((i
< ARRAY_SIZE(embKernel_params_list
)) &&
125 (0 != strcmp(embKernel_params_list
[i
].target_name
, target
->type
->name
)))
128 if (i
>= ARRAY_SIZE(embKernel_params_list
)) {
129 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
130 "list", target
->type
->name
);
134 target
->rtos
->rtos_specific_params
= (void *) &embKernel_params_list
[i
];
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
)
142 int retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_task_owner_offset
, param
->pointer_width
,
144 if (retval
!= ERROR_OK
)
146 details
->threadid
= (threadid_t
) task
;
147 details
->exists
= true;
148 details
->display_str
= NULL
;
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
)
156 details
->thread_name_str
= malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
);
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
)
162 details
->thread_name_str
[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
- 1] = 0;
164 snprintf(details
->thread_name_str
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
, "NoName:[0x%08X]", (unsigned int) task
);
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
)
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
);
177 snprintf(details
->extra_info_str
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
, "Pri=%u, %s", (unsigned int) priority
,
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
);
186 static int embKernel_update_threads(struct rtos
*rtos
)
190 const struct embKernel_params
*param
;
195 if (rtos
->rtos_specific_params
== NULL
)
198 if (rtos
->symbols
== NULL
) {
199 LOG_ERROR("No symbols for embKernel");
203 if (rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
== 0) {
204 LOG_ERROR("Don't have the thread list head");
208 /* wipe out previous thread details if any */
209 if (rtos
->thread_details
!= NULL
) {
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
;
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
;
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
;
225 free(rtos
->thread_details
);
226 rtos
->thread_details
= NULL
;
229 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
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");
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
)
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
);
248 if (retval
!= ERROR_OK
) {
249 LOG_ERROR("Could not read embKernel thread count from target");
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
);
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
)
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
)
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
)
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
)
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
)
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
)
300 /* Look for suspended tasks */
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
)
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
)
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
)
318 rtos
->thread_count
= 0;
319 rtos
->thread_count
= threadIdx
;
320 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx
);
324 static int embKernel_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
327 const struct embKernel_params
*param
;
328 int64_t stack_ptr
= 0;
330 *hex_reg_list
= NULL
;
337 if (rtos
->rtos_specific_params
== NULL
)
340 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
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");
350 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, hex_reg_list
);
353 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
356 *symbol_list
= (symbol_table_elem_t
*) malloc(sizeof(symbol_table_elem_t
) * ARRAY_SIZE(embKernel_symbol_list
));
358 for (i
= 0; i
< ARRAY_SIZE(embKernel_symbol_list
); i
++)
359 (*symbol_list
)[i
].symbol_name
= embKernel_symbol_list
[i
];