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 const char * const 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 static const struct embKernel_params embKernel_params_list
[] = {
86 "cortex_m", /* 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_M_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_M_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
= 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 rtos_free_threadlist(rtos
);
211 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
213 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
, param
->pointer_width
,
214 (uint8_t *) &rtos
->current_thread
);
215 if (retval
!= ERROR_OK
) {
216 LOG_ERROR("Error reading current thread in embKernel thread list");
220 int64_t max_used_priority
= 0;
221 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sMaxPriorities
].address
, param
->pointer_width
,
222 (uint8_t *) &max_used_priority
);
223 if (retval
!= ERROR_OK
)
226 int thread_list_size
= 0;
227 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sCurrentTaskCount
].address
,
228 param
->thread_count_width
, (uint8_t *) &thread_list_size
);
230 if (retval
!= ERROR_OK
) {
231 LOG_ERROR("Could not read embKernel thread count from target");
235 /* create space for new thread details */
236 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
237 if (!rtos
->thread_details
) {
238 LOG_ERROR("Error allocating memory for %d threads", thread_list_size
);
243 /* Look for ready tasks */
244 for (int pri
= 0; pri
< max_used_priority
; pri
++) {
245 /* Get first item in queue */
246 int64_t iterable
= 0;
247 retval
= target_read_buffer(rtos
->target
,
248 rtos
->symbols
[SYMBOL_ID_sListReady
].address
+ (pri
* param
->rtos_list_size
), param
->pointer_width
,
249 (uint8_t *) &iterable
);
250 if (retval
!= ERROR_OK
)
252 for (; iterable
&& threadIdx
< thread_list_size
; threadIdx
++) {
253 /* Get info from this iterable item */
254 retval
= embKernel_get_tasks_details(rtos
, iterable
, param
, &rtos
->thread_details
[threadIdx
], "Ready");
255 if (retval
!= ERROR_OK
)
257 /* Get next iterable item */
258 retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_next_offset
, param
->pointer_width
,
259 (uint8_t *) &iterable
);
260 if (retval
!= ERROR_OK
)
264 /* Look for sleeping tasks */
265 int64_t iterable
= 0;
266 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sListSleep
].address
, 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
], "Sleeping");
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 suspended tasks */
284 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sListSuspended
].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
], "Suspended");
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 rtos
->thread_count
= 0;
301 rtos
->thread_count
= threadIdx
;
302 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx
);
306 static int embKernel_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
309 const struct embKernel_params
*param
;
310 int64_t stack_ptr
= 0;
312 *hex_reg_list
= NULL
;
319 if (rtos
->rtos_specific_params
== NULL
)
322 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
324 /* Read the stack pointer */
325 retval
= target_read_buffer(rtos
->target
, thread_id
+ param
->thread_stack_offset
, param
->pointer_width
,
326 (uint8_t *) &stack_ptr
);
327 if (retval
!= ERROR_OK
) {
328 LOG_ERROR("Error reading stack frame from embKernel thread");
332 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, hex_reg_list
);
335 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
338 *symbol_list
= malloc(sizeof(symbol_table_elem_t
) * ARRAY_SIZE(embKernel_symbol_list
));
340 for (i
= 0; i
< ARRAY_SIZE(embKernel_symbol_list
); i
++)
341 (*symbol_list
)[i
].symbol_name
= embKernel_symbol_list
[i
];