OpenOCD
riot.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2015 by Daniel Krebs *
5  * Daniel Krebs - github@daniel-krebs.net *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "rtos.h"
16 #include "helper/log.h"
17 #include "helper/types.h"
18 #include "target/armv7m.h"
19 #include "rtos_riot_stackings.h"
20 
21 static bool riot_detect_rtos(struct target *target);
22 static int riot_create(struct target *target);
23 static int riot_update_threads(struct rtos *rtos);
24 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
25  struct rtos_reg **reg_list, int *num_regs);
26 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
27 
29  int value;
30  const char *desc;
31 };
32 
33 /* refer RIOT sched.h */
34 static const struct riot_thread_state riot_thread_states[] = {
35  { 0, "Stopped" },
36  { 1, "Zombie" },
37  { 2, "Sleeping" },
38  { 3, "Blocked mutex" },
39  { 4, "Blocked receive" },
40  { 5, "Blocked send" },
41  { 6, "Blocked reply" },
42  { 7, "Blocked any flag" },
43  { 8, "Blocked all flags" },
44  { 9, "Blocked mbox" },
45  { 10, "Blocked condition" },
46  { 11, "Running" },
47  { 12, "Pending" },
48 };
49 #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
50 
51 struct riot_params {
52  const char *target_name;
53  unsigned char thread_sp_offset;
54  unsigned char thread_status_offset;
55 };
56 
57 static const struct riot_params riot_params_list[] = {
58  {
59  "cortex_m", /* target_name */
60  0x00, /* thread_sp_offset */
61  0x04, /* thread_status_offset */
62  },
63  { /* STLink */
64  "hla_target", /* target_name */
65  0x00, /* thread_sp_offset */
66  0x04, /* thread_status_offset */
67  }
68 };
69 #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
70 
71 /* Initialize in riot_create() depending on architecture */
73 
80 };
81 
82 struct riot_symbol {
83  const char *const name;
84  bool optional;
85 };
86 
87 /* refer RIOT core/sched.c */
88 static struct riot_symbol const riot_symbol_list[] = {
89  {"sched_threads", false},
90  {"sched_num_threads", false},
91  {"sched_active_pid", false},
92  {"max_threads", false},
93  {"_tcb_name_offset", true},
94  {NULL, false}
95 };
96 
97 const struct rtos_type riot_rtos = {
98  .name = "RIOT",
99  .detect_rtos = riot_detect_rtos,
100  .create = riot_create,
101  .update_threads = riot_update_threads,
102  .get_thread_reg_list = riot_get_thread_reg_list,
103  .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup,
104 };
105 
106 static int riot_update_threads(struct rtos *rtos)
107 {
108  int retval;
109  int tasks_found = 0;
110  const struct riot_params *param;
111 
112  if (!rtos)
113  return ERROR_FAIL;
114 
116  return ERROR_FAIL;
117 
118  param = (const struct riot_params *)rtos->rtos_specific_params;
119 
120  if (!rtos->symbols) {
121  LOG_ERROR("No symbols for RIOT");
122  return ERROR_FAIL;
123  }
124 
125  if (rtos->symbols[RIOT_THREADS_BASE].address == 0) {
126  LOG_ERROR("Can't find symbol `%s`",
128  return ERROR_FAIL;
129  }
130 
131  /* wipe out previous thread details if any */
133 
134  /* Reset values */
135  rtos->current_thread = 0;
136  rtos->thread_count = 0;
137 
138  /* read the current thread id */
139  int16_t active_pid = 0;
140  retval = target_read_u16(rtos->target,
142  (uint16_t *)&active_pid);
143  if (retval != ERROR_OK) {
144  LOG_ERROR("Can't read symbol `%s`",
146  return retval;
147  }
148  rtos->current_thread = active_pid;
149 
150  /* read the current thread count
151  * It's `int` in RIOT, but this is Cortex M* only anyway */
152  int32_t thread_count = 0;
153  retval = target_read_u16(rtos->target,
155  (uint16_t *)&thread_count);
156  if (retval != ERROR_OK) {
157  LOG_ERROR("Can't read symbol `%s`",
159  return retval;
160  }
161 
162  /* read the maximum number of threads */
163  uint8_t max_threads = 0;
164  retval = target_read_u8(rtos->target,
166  &max_threads);
167  if (retval != ERROR_OK) {
168  LOG_ERROR("Can't read symbol `%s`",
170  return retval;
171  }
172  if (thread_count > max_threads) {
173  LOG_ERROR("Thread count is invalid");
174  return ERROR_FAIL;
175  }
176  rtos->thread_count = thread_count;
177 
178  /* Base address of thread array */
179  uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
180 
181  /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
182  * with DEVELHELP, so there are no thread names */
183  uint8_t name_offset = 0;
184  if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) {
185  retval = target_read_u8(rtos->target,
187  &name_offset);
188  if (retval != ERROR_OK) {
189  LOG_ERROR("Can't read symbol `%s`",
191  return retval;
192  }
193  }
194 
195  /* Allocate memory for thread description */
196  rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail));
197  if (!rtos->thread_details) {
198  LOG_ERROR("RIOT: out of memory");
199  return ERROR_FAIL;
200  }
201 
202  /* Buffer for thread names, maximum to display is 32 */
203  char buffer[32];
204 
205  for (unsigned int i = 0; i < max_threads; i++) {
206  if (tasks_found == rtos->thread_count)
207  break;
208 
209  /* get pointer to tcb_t */
210  uint32_t tcb_pointer = 0;
211  retval = target_read_u32(rtos->target,
212  threads_base + (i * 4),
213  &tcb_pointer);
214  if (retval != ERROR_OK) {
215  LOG_ERROR("Can't parse `%s`",
217  goto error;
218  }
219 
220  if (tcb_pointer == 0) {
221  /* PID unused */
222  continue;
223  }
224 
225  /* Index is PID */
226  rtos->thread_details[tasks_found].threadid = i;
227 
228  /* read thread state */
229  uint8_t status = 0;
230  retval = target_read_u8(rtos->target,
231  tcb_pointer + param->thread_status_offset,
232  &status);
233  if (retval != ERROR_OK) {
234  LOG_ERROR("Can't parse `%s`",
236  goto error;
237  }
238 
239  /* Search for state */
240  unsigned int k;
241  for (k = 0; k < RIOT_NUM_STATES; k++) {
242  if (riot_thread_states[k].value == status)
243  break;
244  }
245 
246  /* Copy state string */
247  if (k >= RIOT_NUM_STATES) {
248  rtos->thread_details[tasks_found].extra_info_str =
249  strdup("unknown state");
250  } else {
251  rtos->thread_details[tasks_found].extra_info_str =
252  strdup(riot_thread_states[k].desc);
253  }
254 
255  if (!rtos->thread_details[tasks_found].extra_info_str) {
256  LOG_ERROR("RIOT: out of memory");
257  retval = ERROR_FAIL;
258  goto error;
259  }
260 
261  /* Thread names are only available if compiled with DEVELHELP */
262  if (name_offset != 0) {
263  uint32_t name_pointer = 0;
264  retval = target_read_u32(rtos->target,
265  tcb_pointer + name_offset,
266  &name_pointer);
267  if (retval != ERROR_OK) {
268  LOG_ERROR("Can't parse `%s`",
270  goto error;
271  }
272 
273  /* read thread name */
274  retval = target_read_buffer(rtos->target,
275  name_pointer,
276  sizeof(buffer),
277  (uint8_t *)&buffer);
278  if (retval != ERROR_OK) {
279  LOG_ERROR("Can't parse `%s`",
281  goto error;
282  }
283 
284  /* Make sure the string in the buffer terminates */
285  if (buffer[sizeof(buffer) - 1] != 0)
286  buffer[sizeof(buffer) - 1] = 0;
287 
288  /* Copy thread name */
289  rtos->thread_details[tasks_found].thread_name_str =
290  strdup(buffer);
291 
292  } else {
293  rtos->thread_details[tasks_found].thread_name_str =
294  strdup("Enable DEVELHELP to see task names");
295  }
296 
297  if (!rtos->thread_details[tasks_found].thread_name_str) {
298  LOG_ERROR("RIOT: out of memory");
299  retval = ERROR_FAIL;
300  goto error;
301  }
302 
303  rtos->thread_details[tasks_found].exists = true;
304 
305  tasks_found++;
306  }
307 
308  return ERROR_OK;
309 
310 error:
312  return retval;
313 }
314 
315 static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
316  struct rtos_reg **reg_list, int *num_regs)
317 {
318  int retval;
319  const struct riot_params *param;
320 
321  if (!rtos)
322  return ERROR_FAIL;
323 
324  if (thread_id == 0)
325  return ERROR_FAIL;
326 
328  return ERROR_FAIL;
329 
330  param = (const struct riot_params *)rtos->rtos_specific_params;
331 
332  /* find the thread with given thread id */
333  uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
334  uint32_t tcb_pointer = 0;
335  retval = target_read_u32(rtos->target,
336  threads_base + (thread_id * 4),
337  &tcb_pointer);
338  if (retval != ERROR_OK) {
339  LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
340  return retval;
341  }
342 
343  /* read stack pointer for that thread */
344  uint32_t stackptr = 0;
345  retval = target_read_u32(rtos->target,
346  tcb_pointer + param->thread_sp_offset,
347  &stackptr);
348  if (retval != ERROR_OK) {
349  LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE].name);
350  return retval;
351  }
352 
355  stackptr,
356  reg_list,
357  num_regs);
358 }
359 
360 static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
361 {
362  *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem));
363 
364  if (!*symbol_list) {
365  LOG_ERROR("RIOT: out of memory");
366  return ERROR_FAIL;
367  }
368 
369  for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) {
370  (*symbol_list)[i].symbol_name = riot_symbol_list[i].name;
371  (*symbol_list)[i].optional = riot_symbol_list[i].optional;
372  }
373 
374  return ERROR_OK;
375 }
376 
377 static bool riot_detect_rtos(struct target *target)
378 {
379  if ((target->rtos->symbols) &&
381  /* looks like RIOT */
382  return true;
383  }
384  return false;
385 }
386 
387 static int riot_create(struct target *target)
388 {
389  unsigned int i = 0;
390 
391  /* lookup if target is supported by RIOT */
392  while ((i < RIOT_NUM_PARAMS) &&
393  (strcmp(riot_params_list[i].target_name, target_type_name(target)) != 0)) {
394  i++;
395  }
396  if (i >= RIOT_NUM_PARAMS) {
397  LOG_ERROR("Could not find target in RIOT compatibility list");
398  return ERROR_FAIL;
399  }
400 
402  target->rtos->current_thread = 0;
404 
405  /* Stacking is different depending on architecture */
406  struct armv7m_common *armv7m_target = target_to_armv7m(target);
407 
408  if (armv7m_target->arm.arch == ARM_ARCH_V6M)
410  else if (is_armv7m(armv7m_target))
412  else {
413  LOG_ERROR("No stacking info for architecture");
414  return ERROR_FAIL;
415  }
416  return ERROR_OK;
417 }
@ ARM_ARCH_V6M
Definition: arm.h:56
const char * name
Definition: armv4_5.c:76
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:262
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:250
The JTAG interface can be implemented with a software or hardware fifo.
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define ERROR_OK
Definition: log.h:164
static const struct rtos_register_stacking * stacking_info
Definition: riot.c:72
static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: riot.c:360
static const struct riot_thread_state riot_thread_states[]
Definition: riot.c:34
static bool riot_detect_rtos(struct target *target)
Definition: riot.c:377
static int riot_update_threads(struct rtos *rtos)
Definition: riot.c:106
static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: riot.c:315
static struct riot_symbol const riot_symbol_list[]
Definition: riot.c:88
const struct rtos_type riot_rtos
Definition: riot.c:97
#define RIOT_NUM_PARAMS
Definition: riot.c:69
#define RIOT_NUM_STATES
Definition: riot.c:49
static const struct riot_params riot_params_list[]
Definition: riot.c:57
static int riot_create(struct target *target)
Definition: riot.c:387
riot_symbol_values
Definition: riot.c:74
@ RIOT_NAME_OFFSET
Definition: riot.c:79
@ RIOT_NUM_THREADS
Definition: riot.c:76
@ RIOT_ACTIVE_PID
Definition: riot.c:77
@ RIOT_THREADS_BASE
Definition: riot.c:75
@ RIOT_MAX_THREADS
Definition: riot.c:78
int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs)
Definition: rtos.c:602
void rtos_free_threadlist(struct rtos *rtos)
Definition: rtos.c:695
const struct rtos_register_stacking rtos_riot_cortex_m0_stacking
const struct rtos_register_stacking rtos_riot_cortex_m34_stacking
enum arm_arch arch
ARM architecture version.
Definition: arm.h:202
struct arm arm
Definition: armv7m.h:225
unsigned char thread_sp_offset
Definition: riot.c:53
const char * target_name
Definition: riot.c:52
unsigned char thread_status_offset
Definition: riot.c:54
const char *const name
Definition: riot.c:83
bool optional
Definition: riot.c:84
const char * desc
Definition: riot.c:30
Definition: rtos.h:53
Definition: rtos.h:59
const char * name
Definition: rtos.h:60
Definition: rtos.h:36
int thread_count
Definition: rtos.h:47
struct thread_detail * thread_details
Definition: rtos.h:46
struct symbol_table_elem * symbols
Definition: rtos.h:39
struct target * target
Definition: rtos.h:40
void * rtos_specific_params
Definition: rtos.h:50
threadid_t current_thread
Definition: rtos.h:45
Table should be terminated by an element with NULL in symbol_name.
Definition: rtos.h:23
symbol_address_t address
Definition: rtos.h:25
Definition: target.h:116
struct rtos * rtos
Definition: target.h:183
char * extra_info_str
Definition: rtos.h:33
char * thread_name_str
Definition: rtos.h:32
bool exists
Definition: rtos.h:31
threadid_t threadid
Definition: rtos.h:30
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2407
int target_read_u8(struct target *target, target_addr_t address, uint8_t *value)
Definition: target.c:2598
int target_read_u16(struct target *target, target_addr_t address, uint16_t *value)
Definition: target.c:2574
int target_read_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2550
const char * target_type_name(const struct target *target)
Get the target type name.
Definition: target.c:736
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16
uint8_t status[4]
Definition: vdebug.c:17