1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2015 by Daniel Krebs *
5 * Daniel Krebs - github@daniel-krebs.net *
6 ***************************************************************************/
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "target/armv7m.h"
20 #include "rtos_riot_stackings.h"
22 static bool riot_detect_rtos(struct target
*target
);
23 static int riot_create(struct target
*target
);
24 static int riot_update_threads(struct rtos
*rtos
);
25 static int riot_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
26 struct rtos_reg
**reg_list
, int *num_regs
);
27 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
29 struct riot_thread_state
{
34 /* refer RIOT sched.h */
35 static const struct riot_thread_state riot_thread_states
[] = {
39 { 3, "Blocked mutex" },
40 { 4, "Blocked receive" },
41 { 5, "Blocked send" },
42 { 6, "Blocked reply" },
43 { 7, "Blocked any flag" },
44 { 8, "Blocked all flags" },
45 { 9, "Blocked mbox" },
46 { 10, "Blocked condition" },
50 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
53 const char *target_name
;
54 unsigned char thread_sp_offset
;
55 unsigned char thread_status_offset
;
58 static const struct riot_params riot_params_list
[] = {
60 "cortex_m", /* target_name */
61 0x00, /* thread_sp_offset */
62 0x04, /* thread_status_offset */
65 "hla_target", /* target_name */
66 0x00, /* thread_sp_offset */
67 0x04, /* thread_status_offset */
70 #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
72 /* Initialize in riot_create() depending on architecture */
73 static const struct rtos_register_stacking
*stacking_info
;
75 enum riot_symbol_values
{
76 RIOT_THREADS_BASE
= 0,
84 const char *const name
;
88 /* refer RIOT core/sched.c */
89 static struct riot_symbol
const riot_symbol_list
[] = {
90 {"sched_threads", false},
91 {"sched_num_threads", false},
92 {"sched_active_pid", false},
93 {"max_threads", false},
94 {"_tcb_name_offset", true},
98 const struct rtos_type riot_rtos
= {
100 .detect_rtos
= riot_detect_rtos
,
101 .create
= riot_create
,
102 .update_threads
= riot_update_threads
,
103 .get_thread_reg_list
= riot_get_thread_reg_list
,
104 .get_symbol_list_to_lookup
= riot_get_symbol_list_to_lookup
,
107 static int riot_update_threads(struct rtos
*rtos
)
111 const struct riot_params
*param
;
116 if (!rtos
->rtos_specific_params
)
119 param
= (const struct riot_params
*)rtos
->rtos_specific_params
;
121 if (!rtos
->symbols
) {
122 LOG_ERROR("No symbols for RIOT");
126 if (rtos
->symbols
[RIOT_THREADS_BASE
].address
== 0) {
127 LOG_ERROR("Can't find symbol `%s`",
128 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
132 /* wipe out previous thread details if any */
133 rtos_free_threadlist(rtos
);
136 rtos
->current_thread
= 0;
137 rtos
->thread_count
= 0;
139 /* read the current thread id */
140 int16_t active_pid
= 0;
141 retval
= target_read_u16(rtos
->target
,
142 rtos
->symbols
[RIOT_ACTIVE_PID
].address
,
143 (uint16_t *)&active_pid
);
144 if (retval
!= ERROR_OK
) {
145 LOG_ERROR("Can't read symbol `%s`",
146 riot_symbol_list
[RIOT_ACTIVE_PID
].name
);
149 rtos
->current_thread
= active_pid
;
151 /* read the current thread count
152 * It's `int` in RIOT, but this is Cortex M* only anyway */
153 int32_t thread_count
= 0;
154 retval
= target_read_u16(rtos
->target
,
155 rtos
->symbols
[RIOT_NUM_THREADS
].address
,
156 (uint16_t *)&thread_count
);
157 if (retval
!= ERROR_OK
) {
158 LOG_ERROR("Can't read symbol `%s`",
159 riot_symbol_list
[RIOT_NUM_THREADS
].name
);
163 /* read the maximum number of threads */
164 uint8_t max_threads
= 0;
165 retval
= target_read_u8(rtos
->target
,
166 rtos
->symbols
[RIOT_MAX_THREADS
].address
,
168 if (retval
!= ERROR_OK
) {
169 LOG_ERROR("Can't read symbol `%s`",
170 riot_symbol_list
[RIOT_MAX_THREADS
].name
);
173 if (thread_count
> max_threads
) {
174 LOG_ERROR("Thread count is invalid");
177 rtos
->thread_count
= thread_count
;
179 /* Base address of thread array */
180 uint32_t threads_base
= rtos
->symbols
[RIOT_THREADS_BASE
].address
;
182 /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
183 * with DEVELHELP, so there are no thread names */
184 uint8_t name_offset
= 0;
185 if (rtos
->symbols
[RIOT_NAME_OFFSET
].address
!= 0) {
186 retval
= target_read_u8(rtos
->target
,
187 rtos
->symbols
[RIOT_NAME_OFFSET
].address
,
189 if (retval
!= ERROR_OK
) {
190 LOG_ERROR("Can't read symbol `%s`",
191 riot_symbol_list
[RIOT_NAME_OFFSET
].name
);
196 /* Allocate memory for thread description */
197 rtos
->thread_details
= calloc(thread_count
, sizeof(struct thread_detail
));
198 if (!rtos
->thread_details
) {
199 LOG_ERROR("RIOT: out of memory");
203 /* Buffer for thread names, maximum to display is 32 */
206 for (unsigned int i
= 0; i
< max_threads
; i
++) {
207 if (tasks_found
== rtos
->thread_count
)
210 /* get pointer to tcb_t */
211 uint32_t tcb_pointer
= 0;
212 retval
= target_read_u32(rtos
->target
,
213 threads_base
+ (i
* 4),
215 if (retval
!= ERROR_OK
) {
216 LOG_ERROR("Can't parse `%s`",
217 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
221 if (tcb_pointer
== 0) {
227 rtos
->thread_details
[tasks_found
].threadid
= i
;
229 /* read thread state */
231 retval
= target_read_u8(rtos
->target
,
232 tcb_pointer
+ param
->thread_status_offset
,
234 if (retval
!= ERROR_OK
) {
235 LOG_ERROR("Can't parse `%s`",
236 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
240 /* Search for state */
242 for (k
= 0; k
< RIOT_NUM_STATES
; k
++) {
243 if (riot_thread_states
[k
].value
== status
)
247 /* Copy state string */
248 if (k
>= RIOT_NUM_STATES
) {
249 rtos
->thread_details
[tasks_found
].extra_info_str
=
250 strdup("unknown state");
252 rtos
->thread_details
[tasks_found
].extra_info_str
=
253 strdup(riot_thread_states
[k
].desc
);
256 if (!rtos
->thread_details
[tasks_found
].extra_info_str
) {
257 LOG_ERROR("RIOT: out of memory");
262 /* Thread names are only available if compiled with DEVELHELP */
263 if (name_offset
!= 0) {
264 uint32_t name_pointer
= 0;
265 retval
= target_read_u32(rtos
->target
,
266 tcb_pointer
+ name_offset
,
268 if (retval
!= ERROR_OK
) {
269 LOG_ERROR("Can't parse `%s`",
270 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
274 /* read thread name */
275 retval
= target_read_buffer(rtos
->target
,
279 if (retval
!= ERROR_OK
) {
280 LOG_ERROR("Can't parse `%s`",
281 riot_symbol_list
[RIOT_THREADS_BASE
].name
);
285 /* Make sure the string in the buffer terminates */
286 if (buffer
[sizeof(buffer
) - 1] != 0)
287 buffer
[sizeof(buffer
) - 1] = 0;
289 /* Copy thread name */
290 rtos
->thread_details
[tasks_found
].thread_name_str
=
294 rtos
->thread_details
[tasks_found
].thread_name_str
=
295 strdup("Enable DEVELHELP to see task names");
298 if (!rtos
->thread_details
[tasks_found
].thread_name_str
) {
299 LOG_ERROR("RIOT: out of memory");
304 rtos
->thread_details
[tasks_found
].exists
= true;
312 rtos_free_threadlist(rtos
);
316 static int riot_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
317 struct rtos_reg
**reg_list
, int *num_regs
)
320 const struct riot_params
*param
;
328 if (!rtos
->rtos_specific_params
)
331 param
= (const struct riot_params
*)rtos
->rtos_specific_params
;
333 /* find the thread with given thread id */
334 uint32_t threads_base
= rtos
->symbols
[RIOT_THREADS_BASE
].address
;
335 uint32_t tcb_pointer
= 0;
336 retval
= target_read_u32(rtos
->target
,
337 threads_base
+ (thread_id
* 4),
339 if (retval
!= ERROR_OK
) {
340 LOG_ERROR("Can't parse `%s`", riot_symbol_list
[RIOT_THREADS_BASE
].name
);
344 /* read stack pointer for that thread */
345 uint32_t stackptr
= 0;
346 retval
= target_read_u32(rtos
->target
,
347 tcb_pointer
+ param
->thread_sp_offset
,
349 if (retval
!= ERROR_OK
) {
350 LOG_ERROR("Can't parse `%s`", riot_symbol_list
[RIOT_THREADS_BASE
].name
);
354 return rtos_generic_stack_read(rtos
->target
,
361 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
363 *symbol_list
= calloc(ARRAY_SIZE(riot_symbol_list
), sizeof(struct symbol_table_elem
));
366 LOG_ERROR("RIOT: out of memory");
370 for (unsigned int i
= 0; i
< ARRAY_SIZE(riot_symbol_list
); i
++) {
371 (*symbol_list
)[i
].symbol_name
= riot_symbol_list
[i
].name
;
372 (*symbol_list
)[i
].optional
= riot_symbol_list
[i
].optional
;
378 static bool riot_detect_rtos(struct target
*target
)
380 if ((target
->rtos
->symbols
) &&
381 (target
->rtos
->symbols
[RIOT_THREADS_BASE
].address
!= 0)) {
382 /* looks like RIOT */
388 static int riot_create(struct target
*target
)
392 /* lookup if target is supported by RIOT */
393 while ((i
< RIOT_NUM_PARAMS
) &&
394 (strcmp(riot_params_list
[i
].target_name
, target
->type
->name
) != 0)) {
397 if (i
>= RIOT_NUM_PARAMS
) {
398 LOG_ERROR("Could not find target in RIOT compatibility list");
402 target
->rtos
->rtos_specific_params
= (void *)&riot_params_list
[i
];
403 target
->rtos
->current_thread
= 0;
404 target
->rtos
->thread_details
= NULL
;
406 /* Stacking is different depending on architecture */
407 struct armv7m_common
*armv7m_target
= target_to_armv7m(target
);
409 if (armv7m_target
->arm
.arch
== ARM_ARCH_V6M
)
410 stacking_info
= &rtos_riot_cortex_m0_stacking
;
411 else if (is_armv7m(armv7m_target
))
412 stacking_info
= &rtos_riot_cortex_m34_stacking
;
414 LOG_ERROR("No stacking info for architecture");