Upstream a whole host of RISC-V changes.
[openocd.git] / src / rtos / riot.c
blob8a3874202f33ce10329258e57a219574a74c7c12
1 /***************************************************************************
2 * Copyright (C) 2015 by Daniel Krebs *
3 * Daniel Krebs - github@daniel-krebs.net *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "rtos.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 {
41 int value;
42 const char *desc;
45 /* refer RIOT sched.h */
46 static const struct riot_thread_state riot_thread_states[] = {
47 { 0, "Stopped" },
48 { 1, "Zombie" },
49 { 2, "Sleeping" },
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" },
58 { 11, "Running" },
59 { 12, "Pending" },
61 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
63 struct riot_params {
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 */
75 { /* STLink */
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,
88 RIOT_NUM_THREADS,
89 RIOT_ACTIVE_PID,
90 RIOT_MAX_THREADS,
91 RIOT_NAME_OFFSET,
94 struct riot_symbol {
95 const char *const name;
96 bool optional;
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},
106 {NULL, false}
109 const struct rtos_type riot_rtos = {
110 .name = "RIOT",
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)
120 int retval;
121 int tasks_found = 0;
122 const struct riot_params *param;
124 if (!rtos)
125 return ERROR_FAIL;
127 if (!rtos->rtos_specific_params)
128 return ERROR_FAIL;
130 param = (const struct riot_params *)rtos->rtos_specific_params;
132 if (!rtos->symbols) {
133 LOG_ERROR("No symbols for RIOT");
134 return ERROR_FAIL;
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);
140 return ERROR_FAIL;
143 /* wipe out previous thread details if any */
144 rtos_free_threadlist(rtos);
146 /* Reset values */
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);
158 return retval;
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);
171 return retval;
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,
178 &max_threads);
179 if (retval != ERROR_OK) {
180 LOG_ERROR("Can't read symbol `%s`",
181 riot_symbol_list[RIOT_MAX_THREADS].name);
182 return retval;
184 if (thread_count > max_threads) {
185 LOG_ERROR("Thread count is invalid");
186 return ERROR_FAIL;
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,
199 &name_offset);
200 if (retval != ERROR_OK) {
201 LOG_ERROR("Can't read symbol `%s`",
202 riot_symbol_list[RIOT_NAME_OFFSET].name);
203 return retval;
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");
211 return ERROR_FAIL;
214 /* Buffer for thread names, maximum to display is 32 */
215 char buffer[32];
217 for (unsigned int i = 0; i < max_threads; i++) {
218 if (tasks_found == rtos->thread_count)
219 break;
221 /* get pointer to tcb_t */
222 uint32_t tcb_pointer = 0;
223 retval = target_read_u32(rtos->target,
224 threads_base + (i * 4),
225 &tcb_pointer);
226 if (retval != ERROR_OK) {
227 LOG_ERROR("Can't parse `%s`",
228 riot_symbol_list[RIOT_THREADS_BASE].name);
229 goto error;
232 if (tcb_pointer == 0) {
233 /* PID unused */
234 continue;
237 /* Index is PID */
238 rtos->thread_details[tasks_found].threadid = i;
240 /* read thread state */
241 uint8_t status = 0;
242 retval = target_read_u8(rtos->target,
243 tcb_pointer + param->thread_status_offset,
244 &status);
245 if (retval != ERROR_OK) {
246 LOG_ERROR("Can't parse `%s`",
247 riot_symbol_list[RIOT_THREADS_BASE].name);
248 goto error;
251 /* Search for state */
252 unsigned int k;
253 for (k = 0; k < RIOT_NUM_STATES; k++) {
254 if (riot_thread_states[k].value == status)
255 break;
258 /* Copy state string */
259 if (k >= RIOT_NUM_STATES) {
260 rtos->thread_details[tasks_found].extra_info_str =
261 strdup("unknown state");
262 } else {
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");
269 retval = ERROR_FAIL;
270 goto error;
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,
278 &name_pointer);
279 if (retval != ERROR_OK) {
280 LOG_ERROR("Can't parse `%s`",
281 riot_symbol_list[RIOT_THREADS_BASE].name);
282 goto error;
285 /* read thread name */
286 retval = target_read_buffer(rtos->target,
287 name_pointer,
288 sizeof(buffer),
289 (uint8_t *)&buffer);
290 if (retval != ERROR_OK) {
291 LOG_ERROR("Can't parse `%s`",
292 riot_symbol_list[RIOT_THREADS_BASE].name);
293 goto error;
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 =
302 strdup(buffer);
304 } else {
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");
311 retval = ERROR_FAIL;
312 goto error;
315 rtos->thread_details[tasks_found].exists = true;
317 tasks_found++;
320 return ERROR_OK;
322 error:
323 rtos_free_threadlist(rtos);
324 return retval;
327 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
328 struct rtos_reg **reg_list, int *num_regs)
330 int retval;
331 const struct riot_params *param;
333 if (!rtos)
334 return ERROR_FAIL;
336 if (thread_id == 0)
337 return ERROR_FAIL;
339 if (!rtos->rtos_specific_params)
340 return ERROR_FAIL;
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),
349 &tcb_pointer);
350 if (retval != ERROR_OK) {
351 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
352 return retval;
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,
359 &stackptr);
360 if (retval != ERROR_OK) {
361 LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
362 return retval;
365 return rtos_generic_stack_read(rtos->target,
366 stacking_info,
367 stackptr,
368 reg_list,
369 num_regs);
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));
376 if (!*symbol_list) {
377 LOG_ERROR("RIOT: out of memory");
378 return ERROR_FAIL;
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;
386 return ERROR_OK;
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 */
394 return true;
396 return false;
399 static int riot_create(struct target *target)
401 unsigned int i = 0;
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)) {
406 i++;
408 if (i >= RIOT_NUM_PARAMS) {
409 LOG_ERROR("Could not find target in RIOT compatibility list");
410 return ERROR_FAIL;
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;
424 else {
425 LOG_ERROR("No stacking info for architecture");
426 return ERROR_FAIL;
428 return ERROR_OK;