1 /***************************************************************************
2 * Copyright (C) 2015 by Daniel Krebs *
3 * Daniel Krebs - github@daniel-krebs.net *
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 "target/armv7m.h"
31 #include "rtos_riot_stackings.h"
33 static bool riot_detect_rtos(struct target
*target
);
34 static int riot_create(struct target
*target
);
35 static int riot_update_threads(struct rtos
*rtos
);
36 static int riot_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
37 struct rtos_reg
**reg_list
, int *num_regs
);
38 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
40 struct riot_thread_state
{
45 /* refer RIOT sched.h */
46 static const struct riot_thread_state riot_thread_states
[] = {
50 { 3, "Blocked mutex" },
51 { 4, "Blocked receive" },
52 { 5, "Blocked send" },
53 { 6, "Blocked reply" },
54 { 7, "Blocked any flag" },
55 { 8, "Blocked all flags" },
56 { 9, "Blocked mbox" },
57 { 10, "Blocked condition" },
61 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
64 const char *target_name
;
65 unsigned char thread_sp_offset
;
66 unsigned char thread_status_offset
;
69 static const struct riot_params riot_params_list
[] = {
71 "cortex_m", /* target_name */
72 0x00, /* thread_sp_offset */
73 0x04, /* thread_status_offset */
76 "hla_target", /* target_name */
77 0x00, /* thread_sp_offset */
78 0x04, /* thread_status_offset */
81 #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
83 /* Initialize in riot_create() depending on architecture */
84 static const struct rtos_register_stacking
*stacking_info
;
86 enum riot_symbol_values
{
87 RIOT_THREADS_BASE
= 0,
95 const char *const name
;
99 /* refer RIOT core/sched.c */
100 static struct riot_symbol
const riot_symbol_list
[] = {
101 {"sched_threads", false},
102 {"sched_num_threads", false},
103 {"sched_active_pid", false},
104 {"max_threads", false},
105 {"_tcb_name_offset", true},
109 const struct rtos_type riot_rtos
= {
111 .detect_rtos
= riot_detect_rtos
,
112 .create
= riot_create
,
113 .update_threads
= riot_update_threads
,
114 .get_thread_reg_list
= riot_get_thread_reg_list
,
115 .get_symbol_list_to_lookup
= riot_get_symbol_list_to_lookup
,
118 static int riot_update_threads(struct rtos
*rtos
)
122 const struct riot_params
*param
;
127 if (!rtos
->rtos_specific_params
)
130 param
= (const struct riot_params
*)rtos
->rtos_specific_params
;
132 if (!rtos
->symbols
) {
133 LOG_ERROR("No symbols for RIOT");
137 if (rtos
->symbols
[RIOT_THREADS_BASE
].address
== 0) {
138 LOG_ERROR("Can't find symbol `%s`",
139 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
143 /* wipe out previous thread details if any */
144 rtos_free_threadlist(rtos
);
147 rtos
->current_thread
= 0;
148 rtos
->thread_count
= 0;
150 /* read the current thread id */
151 int16_t active_pid
= 0;
152 retval
= target_read_u16(rtos
->target
,
153 rtos
->symbols
[RIOT_ACTIVE_PID
].address
,
154 (uint16_t *)&active_pid
);
155 if (retval
!= ERROR_OK
) {
156 LOG_ERROR("Can't read symbol `%s`",
157 riot_symbol_list
[RIOT_ACTIVE_PID
].name
);
160 rtos
->current_thread
= active_pid
;
162 /* read the current thread count
163 * It's `int` in RIOT, but this is Cortex M* only anyway */
164 int32_t thread_count
= 0;
165 retval
= target_read_u16(rtos
->target
,
166 rtos
->symbols
[RIOT_NUM_THREADS
].address
,
167 (uint16_t *)&thread_count
);
168 if (retval
!= ERROR_OK
) {
169 LOG_ERROR("Can't read symbol `%s`",
170 riot_symbol_list
[RIOT_NUM_THREADS
].name
);
174 /* read the maximum number of threads */
175 uint8_t max_threads
= 0;
176 retval
= target_read_u8(rtos
->target
,
177 rtos
->symbols
[RIOT_MAX_THREADS
].address
,
179 if (retval
!= ERROR_OK
) {
180 LOG_ERROR("Can't read symbol `%s`",
181 riot_symbol_list
[RIOT_MAX_THREADS
].name
);
184 if (thread_count
> max_threads
) {
185 LOG_ERROR("Thread count is invalid");
188 rtos
->thread_count
= thread_count
;
190 /* Base address of thread array */
191 uint32_t threads_base
= rtos
->symbols
[RIOT_THREADS_BASE
].address
;
193 /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
194 * with DEVELHELP, so there are no thread names */
195 uint8_t name_offset
= 0;
196 if (rtos
->symbols
[RIOT_NAME_OFFSET
].address
!= 0) {
197 retval
= target_read_u8(rtos
->target
,
198 rtos
->symbols
[RIOT_NAME_OFFSET
].address
,
200 if (retval
!= ERROR_OK
) {
201 LOG_ERROR("Can't read symbol `%s`",
202 riot_symbol_list
[RIOT_NAME_OFFSET
].name
);
207 /* Allocate memory for thread description */
208 rtos
->thread_details
= calloc(thread_count
, sizeof(struct thread_detail
));
209 if (!rtos
->thread_details
) {
210 LOG_ERROR("RIOT: out of memory");
214 /* Buffer for thread names, maximum to display is 32 */
217 for (unsigned int i
= 0; i
< max_threads
; i
++) {
218 if (tasks_found
== rtos
->thread_count
)
221 /* get pointer to tcb_t */
222 uint32_t tcb_pointer
= 0;
223 retval
= target_read_u32(rtos
->target
,
224 threads_base
+ (i
* 4),
226 if (retval
!= ERROR_OK
) {
227 LOG_ERROR("Can't parse `%s`",
228 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
232 if (tcb_pointer
== 0) {
238 rtos
->thread_details
[tasks_found
].threadid
= i
;
240 /* read thread state */
242 retval
= target_read_u8(rtos
->target
,
243 tcb_pointer
+ param
->thread_status_offset
,
245 if (retval
!= ERROR_OK
) {
246 LOG_ERROR("Can't parse `%s`",
247 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
251 /* Search for state */
253 for (k
= 0; k
< RIOT_NUM_STATES
; k
++) {
254 if (riot_thread_states
[k
].value
== status
)
258 /* Copy state string */
259 if (k
>= RIOT_NUM_STATES
) {
260 rtos
->thread_details
[tasks_found
].extra_info_str
=
261 strdup("unknown state");
263 rtos
->thread_details
[tasks_found
].extra_info_str
=
264 strdup(riot_thread_states
[k
].desc
);
267 if (!rtos
->thread_details
[tasks_found
].extra_info_str
) {
268 LOG_ERROR("RIOT: out of memory");
273 /* Thread names are only available if compiled with DEVELHELP */
274 if (name_offset
!= 0) {
275 uint32_t name_pointer
= 0;
276 retval
= target_read_u32(rtos
->target
,
277 tcb_pointer
+ name_offset
,
279 if (retval
!= ERROR_OK
) {
280 LOG_ERROR("Can't parse `%s`",
281 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
285 /* read thread name */
286 retval
= target_read_buffer(rtos
->target
,
290 if (retval
!= ERROR_OK
) {
291 LOG_ERROR("Can't parse `%s`",
292 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
296 /* Make sure the string in the buffer terminates */
297 if (buffer
[sizeof(buffer
) - 1] != 0)
298 buffer
[sizeof(buffer
) - 1] = 0;
300 /* Copy thread name */
301 rtos
->thread_details
[tasks_found
].thread_name_str
=
305 rtos
->thread_details
[tasks_found
].thread_name_str
=
306 strdup("Enable DEVELHELP to see task names");
309 if (!rtos
->thread_details
[tasks_found
].thread_name_str
) {
310 LOG_ERROR("RIOT: out of memory");
315 rtos
->thread_details
[tasks_found
].exists
= true;
323 rtos_free_threadlist(rtos
);
327 static int riot_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
328 struct rtos_reg
**reg_list
, int *num_regs
)
331 const struct riot_params
*param
;
339 if (!rtos
->rtos_specific_params
)
342 param
= (const struct riot_params
*)rtos
->rtos_specific_params
;
344 /* find the thread with given thread id */
345 uint32_t threads_base
= rtos
->symbols
[RIOT_THREADS_BASE
].address
;
346 uint32_t tcb_pointer
= 0;
347 retval
= target_read_u32(rtos
->target
,
348 threads_base
+ (thread_id
* 4),
350 if (retval
!= ERROR_OK
) {
351 LOG_ERROR("Can't parse `%s`", riot_symbol_list
[RIOT_THREADS_BASE
].name
);
355 /* read stack pointer for that thread */
356 uint32_t stackptr
= 0;
357 retval
= target_read_u32(rtos
->target
,
358 tcb_pointer
+ param
->thread_sp_offset
,
360 if (retval
!= ERROR_OK
) {
361 LOG_ERROR("Can't parse `%s`", riot_symbol_list
[RIOT_THREADS_BASE
].name
);
365 return rtos_generic_stack_read(rtos
->target
,
372 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
374 *symbol_list
= calloc(ARRAY_SIZE(riot_symbol_list
), sizeof(struct symbol_table_elem
));
377 LOG_ERROR("RIOT: out of memory");
381 for (unsigned int i
= 0; i
< ARRAY_SIZE(riot_symbol_list
); i
++) {
382 (*symbol_list
)[i
].symbol_name
= riot_symbol_list
[i
].name
;
383 (*symbol_list
)[i
].optional
= riot_symbol_list
[i
].optional
;
389 static bool riot_detect_rtos(struct target
*target
)
391 if ((target
->rtos
->symbols
) &&
392 (target
->rtos
->symbols
[RIOT_THREADS_BASE
].address
!= 0)) {
393 /* looks like RIOT */
399 static int riot_create(struct target
*target
)
403 /* lookup if target is supported by RIOT */
404 while ((i
< RIOT_NUM_PARAMS
) &&
405 (strcmp(riot_params_list
[i
].target_name
, target
->type
->name
) != 0)) {
408 if (i
>= RIOT_NUM_PARAMS
) {
409 LOG_ERROR("Could not find target in RIOT compatibility list");
413 target
->rtos
->rtos_specific_params
= (void *)&riot_params_list
[i
];
414 target
->rtos
->current_thread
= 0;
415 target
->rtos
->thread_details
= NULL
;
417 /* Stacking is different depending on architecture */
418 struct armv7m_common
*armv7m_target
= target_to_armv7m(target
);
420 if (armv7m_target
->arm
.arch
== ARM_ARCH_V6M
)
421 stacking_info
= &rtos_riot_cortex_m0_stacking
;
422 else if (is_armv7m(armv7m_target
))
423 stacking_info
= &rtos_riot_cortex_m34_stacking
;
425 LOG_ERROR("No stacking info for architecture");