flash/nor/rp2040: check target halted before flash operation
[openocd.git] / src / rtos / riot.c
blobbe5452e9e73bdac95adfae0518a4686242f998dd
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 ***************************************************************************/
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.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 {
30 int value;
31 const char *desc;
34 /* refer RIOT sched.h */
35 static const struct riot_thread_state riot_thread_states[] = {
36 { 0, "Stopped" },
37 { 1, "Zombie" },
38 { 2, "Sleeping" },
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" },
47 { 11, "Running" },
48 { 12, "Pending" },
50 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
52 struct riot_params {
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 */
64 { /* STLink */
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,
77 RIOT_NUM_THREADS,
78 RIOT_ACTIVE_PID,
79 RIOT_MAX_THREADS,
80 RIOT_NAME_OFFSET,
83 struct riot_symbol {
84 const char *const name;
85 bool optional;
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},
95 {NULL, false}
98 const struct rtos_type riot_rtos = {
99 .name = "RIOT",
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)
109 int retval;
110 int tasks_found = 0;
111 const struct riot_params *param;
113 if (!rtos)
114 return ERROR_FAIL;
116 if (!rtos->rtos_specific_params)
117 return ERROR_FAIL;
119 param = (const struct riot_params *)rtos->rtos_specific_params;
121 if (!rtos->symbols) {
122 LOG_ERROR("No symbols for RIOT");
123 return ERROR_FAIL;
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);
129 return ERROR_FAIL;
132 /* wipe out previous thread details if any */
133 rtos_free_threadlist(rtos);
135 /* Reset values */
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);
147 return retval;
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);
160 return retval;
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,
167 &max_threads);
168 if (retval != ERROR_OK) {
169 LOG_ERROR("Can't read symbol `%s`",
170 riot_symbol_list[RIOT_MAX_THREADS].name);
171 return retval;
173 if (thread_count > max_threads) {
174 LOG_ERROR("Thread count is invalid");
175 return ERROR_FAIL;
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,
188 &name_offset);
189 if (retval != ERROR_OK) {
190 LOG_ERROR("Can't read symbol `%s`",
191 riot_symbol_list[RIOT_NAME_OFFSET].name);
192 return retval;
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");
200 return ERROR_FAIL;
203 /* Buffer for thread names, maximum to display is 32 */
204 char buffer[32];
206 for (unsigned int i = 0; i < max_threads; i++) {
207 if (tasks_found == rtos->thread_count)
208 break;
210 /* get pointer to tcb_t */
211 uint32_t tcb_pointer = 0;
212 retval = target_read_u32(rtos->target,
213 threads_base + (i * 4),
214 &tcb_pointer);
215 if (retval != ERROR_OK) {
216 LOG_ERROR("Can't parse `%s`",
217 riot_symbol_list[RIOT_THREADS_BASE].name);
218 goto error;
221 if (tcb_pointer == 0) {
222 /* PID unused */
223 continue;
226 /* Index is PID */
227 rtos->thread_details[tasks_found].threadid = i;
229 /* read thread state */
230 uint8_t status = 0;
231 retval = target_read_u8(rtos->target,
232 tcb_pointer + param->thread_status_offset,
233 &status);
234 if (retval != ERROR_OK) {
235 LOG_ERROR("Can't parse `%s`",
236 riot_symbol_list[RIOT_THREADS_BASE].name);
237 goto error;
240 /* Search for state */
241 unsigned int k;
242 for (k = 0; k < RIOT_NUM_STATES; k++) {
243 if (riot_thread_states[k].value == status)
244 break;
247 /* Copy state string */
248 if (k >= RIOT_NUM_STATES) {
249 rtos->thread_details[tasks_found].extra_info_str =
250 strdup("unknown state");
251 } else {
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");
258 retval = ERROR_FAIL;
259 goto error;
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,
267 &name_pointer);
268 if (retval != ERROR_OK) {
269 LOG_ERROR("Can't parse `%s`",
270 riot_symbol_list[RIOT_THREADS_BASE].name);
271 goto error;
274 /* read thread name */
275 retval = target_read_buffer(rtos->target,
276 name_pointer,
277 sizeof(buffer),
278 (uint8_t *)&buffer);
279 if (retval != ERROR_OK) {
280 LOG_ERROR("Can't parse `%s`",
281 riot_symbol_list[RIOT_THREADS_BASE].name);
282 goto error;
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 =
291 strdup(buffer);
293 } else {
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");
300 retval = ERROR_FAIL;
301 goto error;
304 rtos->thread_details[tasks_found].exists = true;
306 tasks_found++;
309 return ERROR_OK;
311 error:
312 rtos_free_threadlist(rtos);
313 return retval;
316 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
317 struct rtos_reg **reg_list, int *num_regs)
319 int retval;
320 const struct riot_params *param;
322 if (!rtos)
323 return ERROR_FAIL;
325 if (thread_id == 0)
326 return ERROR_FAIL;
328 if (!rtos->rtos_specific_params)
329 return ERROR_FAIL;
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),
338 &tcb_pointer);
339 if (retval != ERROR_OK) {
340 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
341 return retval;
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,
348 &stackptr);
349 if (retval != ERROR_OK) {
350 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
351 return retval;
354 return rtos_generic_stack_read(rtos->target,
355 stacking_info,
356 stackptr,
357 reg_list,
358 num_regs);
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));
365 if (!*symbol_list) {
366 LOG_ERROR("RIOT: out of memory");
367 return ERROR_FAIL;
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;
375 return ERROR_OK;
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 */
383 return true;
385 return false;
388 static int riot_create(struct target *target)
390 unsigned int i = 0;
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)) {
395 i++;
397 if (i >= RIOT_NUM_PARAMS) {
398 LOG_ERROR("Could not find target in RIOT compatibility list");
399 return ERROR_FAIL;
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;
413 else {
414 LOG_ERROR("No stacking info for architecture");
415 return ERROR_FAIL;
417 return ERROR_OK;