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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_embkernel_stackings.h"
32 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
34 static int embKernel_detect_rtos(struct target
*target
);
35 static int embKernel_create(struct target
*target
);
36 static int embKernel_update_threads(struct rtos
*rtos
);
37 static int embKernel_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
);
38 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[]);
40 struct rtos_type embKernel_rtos
= {
42 .detect_rtos
= embKernel_detect_rtos
,
43 .create
= embKernel_create
,
44 .update_threads
= embKernel_update_threads
,
45 .get_thread_reg_list
=
46 embKernel_get_thread_reg_list
,
47 .get_symbol_list_to_lookup
= embKernel_get_symbol_list_to_lookup
,
51 SYMBOL_ID_sCurrentTask
= 0,
52 SYMBOL_ID_sListReady
= 1,
53 SYMBOL_ID_sListSleep
= 2,
54 SYMBOL_ID_sListSuspended
= 3,
55 SYMBOL_ID_sMaxPriorities
= 4,
56 SYMBOL_ID_sCurrentTaskCount
= 5,
59 static const char * const embKernel_symbol_list
[] = {
63 "Rtos::sListSuspended",
64 "Rtos::sMaxPriorities",
65 "Rtos::sCurrentTaskCount",
68 struct embKernel_params
{
69 const char *target_name
;
70 const unsigned char pointer_width
;
71 const unsigned char thread_count_width
;
72 const unsigned char rtos_list_size
;
73 const unsigned char thread_stack_offset
;
74 const unsigned char thread_name_offset
;
75 const unsigned char thread_priority_offset
;
76 const unsigned char thread_priority_width
;
77 const unsigned char iterable_next_offset
;
78 const unsigned char iterable_task_owner_offset
;
79 const struct rtos_register_stacking
*stacking_info
;
82 static const struct embKernel_params embKernel_params_list
[] = {
84 "cortex_m", /* target_name */
85 4, /* pointer_width */
86 4, /* thread_count_width */
87 8, /*rtos_list_size */
88 0, /*thread_stack_offset */
89 4, /*thread_name_offset */
90 8, /*thread_priority_offset */
91 4, /*thread_priority_width */
92 4, /*iterable_next_offset */
93 12, /*iterable_task_owner_offset */
94 &rtos_embkernel_Cortex_M_stacking
, /* stacking_info*/
96 { "hla_target", /* target_name */
97 4, /* pointer_width */
98 4, /* thread_count_width */
99 8, /*rtos_list_size */
100 0, /*thread_stack_offset */
101 4, /*thread_name_offset */
102 8, /*thread_priority_offset */
103 4, /*thread_priority_width */
104 4, /*iterable_next_offset */
105 12, /*iterable_task_owner_offset */
106 &rtos_embkernel_Cortex_M_stacking
, /* stacking_info */
110 static int embKernel_detect_rtos(struct target
*target
)
112 if (target
->rtos
->symbols
!= NULL
) {
113 if (target
->rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
!= 0)
119 static int embKernel_create(struct target
*target
)
122 while ((i
< ARRAY_SIZE(embKernel_params_list
)) &&
123 (0 != strcmp(embKernel_params_list
[i
].target_name
, target
->type
->name
)))
126 if (i
>= ARRAY_SIZE(embKernel_params_list
)) {
127 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
128 "list", target
->type
->name
);
132 target
->rtos
->rtos_specific_params
= (void *) &embKernel_params_list
[i
];
136 static int embKernel_get_tasks_details(struct rtos
*rtos
, int64_t iterable
, const struct embKernel_params
*param
,
137 struct thread_detail
*details
, const char* state_str
)
140 int retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_task_owner_offset
, param
->pointer_width
,
142 if (retval
!= ERROR_OK
)
144 details
->threadid
= (threadid_t
) task
;
145 details
->exists
= true;
147 int64_t name_ptr
= 0;
148 retval
= target_read_buffer(rtos
->target
, task
+ param
->thread_name_offset
, param
->pointer_width
,
149 (uint8_t *) &name_ptr
);
150 if (retval
!= ERROR_OK
)
153 details
->thread_name_str
= malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
);
155 retval
= target_read_buffer(rtos
->target
, name_ptr
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
,
156 (uint8_t *) details
->thread_name_str
);
157 if (retval
!= ERROR_OK
)
159 details
->thread_name_str
[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
- 1] = 0;
161 snprintf(details
->thread_name_str
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
, "NoName:[0x%08X]", (unsigned int) task
);
164 int64_t priority
= 0;
165 retval
= target_read_buffer(rtos
->target
, task
+ param
->thread_priority_offset
, param
->thread_priority_width
,
166 (uint8_t *) &priority
);
167 if (retval
!= ERROR_OK
)
169 details
->extra_info_str
= malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
);
170 if (task
== rtos
->current_thread
) {
171 snprintf(details
->extra_info_str
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
, "State: Running, Priority: %u",
172 (unsigned int) priority
);
174 snprintf(details
->extra_info_str
, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE
, "State: %s, Priority: %u",
175 state_str
, (unsigned int) priority
);
178 LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable
,
179 (unsigned int)task
, details
->thread_name_str
);
183 static int embKernel_update_threads(struct rtos
*rtos
)
187 const struct embKernel_params
*param
;
192 if (rtos
->rtos_specific_params
== NULL
)
195 if (rtos
->symbols
== NULL
) {
196 LOG_ERROR("No symbols for embKernel");
200 if (rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
== 0) {
201 LOG_ERROR("Don't have the thread list head");
205 /* wipe out previous thread details if any */
206 rtos_free_threadlist(rtos
);
208 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
210 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sCurrentTask
].address
, param
->pointer_width
,
211 (uint8_t *) &rtos
->current_thread
);
212 if (retval
!= ERROR_OK
) {
213 LOG_ERROR("Error reading current thread in embKernel thread list");
217 int64_t max_used_priority
= 0;
218 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sMaxPriorities
].address
, param
->pointer_width
,
219 (uint8_t *) &max_used_priority
);
220 if (retval
!= ERROR_OK
)
223 int thread_list_size
= 0;
224 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sCurrentTaskCount
].address
,
225 param
->thread_count_width
, (uint8_t *) &thread_list_size
);
227 if (retval
!= ERROR_OK
) {
228 LOG_ERROR("Could not read embKernel thread count from target");
232 /* create space for new thread details */
233 rtos
->thread_details
= malloc(sizeof(struct thread_detail
) * thread_list_size
);
234 if (!rtos
->thread_details
) {
235 LOG_ERROR("Error allocating memory for %d threads", thread_list_size
);
240 /* Look for ready tasks */
241 for (int pri
= 0; pri
< max_used_priority
; pri
++) {
242 /* Get first item in queue */
243 int64_t iterable
= 0;
244 retval
= target_read_buffer(rtos
->target
,
245 rtos
->symbols
[SYMBOL_ID_sListReady
].address
+ (pri
* param
->rtos_list_size
), param
->pointer_width
,
246 (uint8_t *) &iterable
);
247 if (retval
!= ERROR_OK
)
249 for (; iterable
&& threadIdx
< thread_list_size
; threadIdx
++) {
250 /* Get info from this iterable item */
251 retval
= embKernel_get_tasks_details(rtos
, iterable
, param
, &rtos
->thread_details
[threadIdx
], "Ready");
252 if (retval
!= ERROR_OK
)
254 /* Get next iterable item */
255 retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_next_offset
, param
->pointer_width
,
256 (uint8_t *) &iterable
);
257 if (retval
!= ERROR_OK
)
261 /* Look for sleeping tasks */
262 int64_t iterable
= 0;
263 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sListSleep
].address
, param
->pointer_width
,
264 (uint8_t *) &iterable
);
265 if (retval
!= ERROR_OK
)
267 for (; iterable
&& threadIdx
< thread_list_size
; threadIdx
++) {
268 /*Get info from this iterable item */
269 retval
= embKernel_get_tasks_details(rtos
, iterable
, param
, &rtos
->thread_details
[threadIdx
], "Sleeping");
270 if (retval
!= ERROR_OK
)
272 /*Get next iterable item */
273 retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_next_offset
, param
->pointer_width
,
274 (uint8_t *) &iterable
);
275 if (retval
!= ERROR_OK
)
279 /* Look for suspended tasks */
281 retval
= target_read_buffer(rtos
->target
, rtos
->symbols
[SYMBOL_ID_sListSuspended
].address
, param
->pointer_width
,
282 (uint8_t *) &iterable
);
283 if (retval
!= ERROR_OK
)
285 for (; iterable
&& threadIdx
< thread_list_size
; threadIdx
++) {
286 /* Get info from this iterable item */
287 retval
= embKernel_get_tasks_details(rtos
, iterable
, param
, &rtos
->thread_details
[threadIdx
], "Suspended");
288 if (retval
!= ERROR_OK
)
290 /*Get next iterable item */
291 retval
= target_read_buffer(rtos
->target
, iterable
+ param
->iterable_next_offset
, param
->pointer_width
,
292 (uint8_t *) &iterable
);
293 if (retval
!= ERROR_OK
)
297 rtos
->thread_count
= 0;
298 rtos
->thread_count
= threadIdx
;
299 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx
);
303 static int embKernel_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
306 const struct embKernel_params
*param
;
307 int64_t stack_ptr
= 0;
309 *hex_reg_list
= NULL
;
316 if (rtos
->rtos_specific_params
== NULL
)
319 param
= (const struct embKernel_params
*) rtos
->rtos_specific_params
;
321 /* Read the stack pointer */
322 retval
= target_read_buffer(rtos
->target
, thread_id
+ param
->thread_stack_offset
, param
->pointer_width
,
323 (uint8_t *) &stack_ptr
);
324 if (retval
!= ERROR_OK
) {
325 LOG_ERROR("Error reading stack frame from embKernel thread");
329 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, hex_reg_list
);
332 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
335 *symbol_list
= calloc(ARRAY_SIZE(embKernel_symbol_list
), sizeof(symbol_table_elem_t
));
337 for (i
= 0; i
< ARRAY_SIZE(embKernel_symbol_list
); i
++)
338 (*symbol_list
)[i
].symbol_name
= embKernel_symbol_list
[i
];