OpenOCD
chibios.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2012 by Matthias Blaicher *
5  * Matthias Blaicher - matthias@blaicher.com *
6  * *
7  * Copyright (C) 2011 by Broadcom Corporation *
8  * Evan Hunter - ehunter@broadcom.com *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include <helper/time_support.h>
16 #include <jtag/jtag.h>
17 #include "target/target.h"
18 #include "target/armv7m.h"
19 #include "target/cortex_m.h"
20 #include "rtos.h"
21 #include "helper/log.h"
22 #include "helper/types.h"
23 #include "rtos_chibios_stackings.h"
24 
31  char ch_identifier[4];
32  uint8_t ch_zero;
33  uint8_t ch_size;
34  uint8_t ch_version[2];
35  uint8_t ch_ptrsize;
36  uint8_t ch_timesize;
37  uint8_t ch_threadsize;
38  uint8_t cf_off_prio;
39  uint8_t cf_off_ctx;
40  uint8_t cf_off_newer;
41  uint8_t cf_off_older;
42  uint8_t cf_off_name;
43  uint8_t cf_off_stklimit;
45  uint8_t cf_off_state;
46  uint8_t cf_off_flags;
47  uint8_t cf_off_refs;
48  uint8_t cf_off_preempt;
50  uint8_t cf_off_time;
51 };
52 
53 #define GET_CH_KERNEL_MAJOR(coded_version) ((coded_version >> 11) & 0x1f)
54 #define GET_CH_KERNEL_MINOR(coded_version) ((coded_version >> 6) & 0x1f)
55 #define GET_CH_KERNEL_PATCH(coded_version) ((coded_version >> 0) & 0x3f)
56 
60 static const char * const chibios_thread_states[] = { "READY", "CURRENT",
61 "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING",
62 "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL"
63 };
64 
65 #define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states)
66 
67 /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
68  * chars ought to be enough.
69  */
70 #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
71 
73  const char *target_name;
74 
77 };
78 
79 static struct chibios_params chibios_params_list[] = {
80  {
81  "cortex_m", /* target_name */
82  NULL,
83  NULL, /* stacking_info */
84  },
85  {
86  "hla_target", /* target_name */
87  NULL,
88  NULL, /* stacking_info */
89  }
90 };
91 
92 static bool chibios_detect_rtos(struct target *target);
93 static int chibios_create(struct target *target);
94 static int chibios_update_threads(struct rtos *rtos);
95 static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
96  struct rtos_reg **reg_list, int *num_regs);
97 static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
98 
99 const struct rtos_type chibios_rtos = {
100  .name = "chibios",
101 
102  .detect_rtos = chibios_detect_rtos,
103  .create = chibios_create,
104  .update_threads = chibios_update_threads,
105  .get_thread_reg_list = chibios_get_thread_reg_list,
106  .get_symbol_list_to_lookup = chibios_get_symbol_list_to_lookup,
107 };
108 
109 
110 /* In ChibiOS/RT 3.0 the rlist structure has become part of a system
111  * data structure ch. We declare both symbols as optional and later
112  * use whatever is available.
113  */
114 
119 };
120 
121 static struct symbol_table_elem chibios_symbol_list[] = {
122  { "rlist", 0, true}, /* Thread ready list */
123  { "ch", 0, true}, /* System data structure */
124  { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */
125  { NULL, 0, false}
126 };
127 
128 /* Offset of the rlist structure within the system data structure (ch) */
129 #define CH_RLIST_OFFSET 0x00
130 
132 {
133  int retval;
134  struct chibios_params *param;
135  struct chibios_chdebug *signature;
136 
137  param = (struct chibios_params *) rtos->rtos_specific_params;
138 
139  /* Free existing memory description.*/
140  free(param->signature);
141  param->signature = NULL;
142 
143  signature = malloc(sizeof(*signature));
144  if (!signature) {
145  LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
146  return -1;
147  }
148 
149  retval = target_read_buffer(rtos->target,
151  sizeof(*signature),
152  (uint8_t *) signature);
153  if (retval != ERROR_OK) {
154  LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
155  goto errfree;
156  }
157 
158  if (strncmp(signature->ch_identifier, "main", 4) != 0) {
159  LOG_ERROR("Memory signature identifier does not contain magic bytes.");
160  goto errfree;
161  }
162 
163  if (signature->ch_size < sizeof(*signature)) {
164  LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
165  "than expected");
166  goto errfree;
167  }
168 
169  if (signature->ch_size > sizeof(*signature)) {
170  LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
171  " expected. Assuming compatibility...");
172  }
173 
174  const uint16_t ch_version = target_buffer_get_u16(rtos->target, signature->ch_version);
175  LOG_INFO("Successfully loaded memory map of ChibiOS/RT target "
176  "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version),
177  GET_CH_KERNEL_MINOR(ch_version), GET_CH_KERNEL_PATCH(ch_version));
178 
179  /* Currently, we have the inherent assumption that all address pointers
180  * are 32 bit wide. */
181  if (signature->ch_ptrsize != sizeof(uint32_t)) {
182  LOG_ERROR("ChibiOS/RT target memory signature claims an address "
183  "width unequal to 32 bits!");
184  free(signature);
185  return -1;
186  }
187 
188  param->signature = signature;
189  return 0;
190 
191 errfree:
192  /* Error reading the ChibiOS memory structure */
193  free(signature);
194  param->signature = NULL;
195  return -1;
196 }
197 
198 
199 static int chibios_update_stacking(struct rtos *rtos)
200 {
201  /* Sometimes the stacking can not be determined only by looking at the
202  * target name but only a runtime.
203  *
204  * For example, this is the case for Cortex-M4 targets and ChibiOS which
205  * only stack the FPU registers if it is enabled during ChibiOS build.
206  *
207  * Terminating which stacking is used is target depending.
208  *
209  * Assumptions:
210  * - Once ChibiOS is actually initialized, the stacking is fixed.
211  * - During startup code, the FPU might not be initialized and the
212  * detection might fail.
213  * - Since no threads are running during startup, the problem is solved
214  * by delaying stacking detection until there are more threads
215  * available than the current execution. In which case
216  * chibios_get_thread_reg_list is called.
217  */
218  int retval;
219 
221  return -1;
222 
223  struct chibios_params *param;
224  param = (struct chibios_params *) rtos->rtos_specific_params;
225 
226  /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */
227  struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
228  if (is_armv7m(armv7m_target)) {
229  if (armv7m_target->fp_feature != FP_NONE) {
230  /* Found ARM v7m target which includes a FPU */
231  uint32_t cpacr;
232 
233  retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
234  if (retval != ERROR_OK) {
235  LOG_ERROR("Could not read CPACR register to check FPU state");
236  return -1;
237  }
238 
239  /* Check if CP10 and CP11 are set to full access.
240  * In ChibiOS this is done in ResetHandler() in crt0.c */
241  if (cpacr & 0x00F00000) {
242  LOG_DEBUG("Enabled FPU detected.");
244  return 0;
245  }
246  }
247 
248  /* Found ARM v7m target with no or disabled FPU */
250  return 0;
251  }
252 
253  return -1;
254 }
255 
256 static int chibios_update_threads(struct rtos *rtos)
257 {
258  int retval;
259  const struct chibios_params *param;
260  int tasks_found = 0;
261  int rtos_valid = -1;
262 
264  return -1;
265 
266  if (!rtos->symbols) {
267  LOG_ERROR("No symbols for ChibiOS");
268  return -3;
269  }
270 
271  param = (const struct chibios_params *) rtos->rtos_specific_params;
272  /* Update the memory signature saved in the target memory */
273  if (!param->signature) {
275  if (retval != ERROR_OK) {
276  LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
277  return retval;
278  }
279  }
280 
281  /* wipe out previous thread details if any */
283 
284  /* ChibiOS does not save the current thread count. We have to first
285  * parse the double linked thread list to check for errors and the number of
286  * threads. */
287  const uint32_t rlist = rtos->symbols[CHIBIOS_VAL_RLIST].address ?
290  const struct chibios_chdebug *signature = param->signature;
291  uint32_t current;
292  uint32_t previous;
293  uint32_t older;
294 
295  current = rlist;
296  previous = rlist;
297  while (1) {
298  retval = target_read_u32(rtos->target,
299  current + signature->cf_off_newer, &current);
300  if (retval != ERROR_OK) {
301  LOG_ERROR("Could not read next ChibiOS thread");
302  return retval;
303  }
304  /* Could be NULL if the kernel is not initialized yet or if the
305  * registry is corrupted. */
306  if (current == 0) {
307  LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
308 
309  rtos_valid = 0;
310  break;
311  }
312  /* Fetch previous thread in the list as a integrity check. */
313  retval = target_read_u32(rtos->target,
314  current + signature->cf_off_older, &older);
315  if ((retval != ERROR_OK) || (older == 0) || (older != previous)) {
316  LOG_ERROR("ChibiOS registry integrity check failed, "
317  "double linked list violation");
318  rtos_valid = 0;
319  break;
320  }
321  /* Check for full iteration of the linked list. */
322  if (current == rlist)
323  break;
324  tasks_found++;
325  previous = current;
326  }
327  if (!rtos_valid) {
328  /* No RTOS, there is always at least the current execution, though */
329  LOG_INFO("Only showing current execution because of a broken "
330  "ChibiOS thread registry.");
331 
332  const char tmp_thread_name[] = "Current Execution";
333  const char tmp_thread_extra_info[] = "No RTOS thread";
334 
335  rtos->thread_details = malloc(
336  sizeof(struct thread_detail));
338  rtos->thread_details->exists = true;
339 
341  sizeof(tmp_thread_extra_info));
342  strcpy(rtos->thread_details->extra_info_str, tmp_thread_extra_info);
343 
345  sizeof(tmp_thread_name));
346  strcpy(rtos->thread_details->thread_name_str, tmp_thread_name);
347 
348  rtos->current_thread = 1;
349  rtos->thread_count = 1;
350  return ERROR_OK;
351  }
352 
353  /* create space for new thread details */
354  rtos->thread_details = malloc(
355  sizeof(struct thread_detail) * tasks_found);
356  if (!rtos->thread_details) {
357  LOG_ERROR("Could not allocate space for thread details");
358  return -1;
359  }
360 
361  rtos->thread_count = tasks_found;
362  /* Loop through linked list. */
363  struct thread_detail *curr_thrd_details = rtos->thread_details;
364  while (curr_thrd_details < rtos->thread_details + tasks_found) {
365  uint32_t name_ptr = 0;
366  char tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE];
367 
368  retval = target_read_u32(rtos->target,
369  current + signature->cf_off_newer, &current);
370  if (retval != ERROR_OK) {
371  LOG_ERROR("Could not read next ChibiOS thread");
372  return -6;
373  }
374 
375  /* Check for full iteration of the linked list. */
376  if (current == rlist)
377  break;
378 
379  /* Save the thread pointer */
380  curr_thrd_details->threadid = current;
381 
382  /* read the name pointer */
383  retval = target_read_u32(rtos->target,
384  current + signature->cf_off_name, &name_ptr);
385  if (retval != ERROR_OK) {
386  LOG_ERROR("Could not read ChibiOS thread name pointer from target");
387  return retval;
388  }
389 
390  /* Read the thread name */
391  retval = target_read_buffer(rtos->target, name_ptr,
393  (uint8_t *)&tmp_str);
394  if (retval != ERROR_OK) {
395  LOG_ERROR("Error reading thread name from ChibiOS target");
396  return retval;
397  }
398  tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE - 1] = '\x00';
399 
400  if (tmp_str[0] == '\x00')
401  strcpy(tmp_str, "No Name");
402 
403  curr_thrd_details->thread_name_str = malloc(
404  strlen(tmp_str) + 1);
405  strcpy(curr_thrd_details->thread_name_str, tmp_str);
406 
407  /* State info */
408  uint8_t thread_state;
409  const char *state_desc;
410 
411  retval = target_read_u8(rtos->target,
412  current + signature->cf_off_state, &thread_state);
413  if (retval != ERROR_OK) {
414  LOG_ERROR("Error reading thread state from ChibiOS target");
415  return retval;
416  }
417 
418 
419  if (thread_state < CHIBIOS_NUM_STATES)
420  state_desc = chibios_thread_states[thread_state];
421  else
422  state_desc = "Unknown";
423 
424  curr_thrd_details->extra_info_str = malloc(strlen(
425  state_desc)+8);
426  sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc);
427 
428  curr_thrd_details->exists = true;
429 
430  curr_thrd_details++;
431  }
432 
433  uint32_t current_thrd;
434  /* NOTE: By design, cf_off_name equals readylist_current_offset */
435  retval = target_read_u32(rtos->target,
436  rlist + signature->cf_off_name,
437  &current_thrd);
438  if (retval != ERROR_OK) {
439  LOG_ERROR("Could not read current Thread from ChibiOS target");
440  return retval;
441  }
442  rtos->current_thread = current_thrd;
443 
444  return 0;
445 }
446 
447 static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
448  struct rtos_reg **reg_list, int *num_regs)
449 {
450  int retval;
451  const struct chibios_params *param;
452  uint32_t stack_ptr = 0;
453 
454  if ((!rtos) || (thread_id == 0) ||
456  return -1;
457 
458  param = (const struct chibios_params *) rtos->rtos_specific_params;
459 
460  if (!param->signature)
461  return -1;
462 
463  /* Update stacking if it can only be determined from runtime information */
464  if (!param->stacking_info &&
466  LOG_ERROR("Failed to determine exact stacking for the target type %s", target_type_name(rtos->target));
467  return -1;
468  }
469 
470  /* Read the stack pointer */
471  retval = target_read_u32(rtos->target,
472  thread_id + param->signature->cf_off_ctx, &stack_ptr);
473  if (retval != ERROR_OK) {
474  LOG_ERROR("Error reading stack frame from ChibiOS thread");
475  return retval;
476  }
477 
478  return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
479 }
480 
481 static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
482 {
483  *symbol_list = malloc(sizeof(chibios_symbol_list));
484 
485  if (!*symbol_list)
486  return ERROR_FAIL;
487 
488  memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list));
489  return 0;
490 }
491 
492 static bool chibios_detect_rtos(struct target *target)
493 {
494  if ((target->rtos->symbols) &&
497 
499  LOG_INFO("It looks like the target may be running ChibiOS "
500  "without ch_debug.");
501  return false;
502  }
503 
504  /* looks like ChibiOS with memory map enabled.*/
505  return true;
506  }
507 
508  return false;
509 }
510 
511 static int chibios_create(struct target *target)
512 {
513  for (unsigned int i = 0; i < ARRAY_SIZE(chibios_params_list); i++)
514  if (strcmp(chibios_params_list[i].target_name, target_type_name(target)) == 0) {
516  return 0;
517  }
518 
519  LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
520  "list", target_type_name(target));
521  return -1;
522 }
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:262
@ FP_NONE
Definition: armv7m.h:210
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:250
#define GET_CH_KERNEL_MINOR(coded_version)
Definition: chibios.c:54
#define CHIBIOS_NUM_STATES
Definition: chibios.c:65
static int chibios_update_stacking(struct rtos *rtos)
Definition: chibios.c:199
static int chibios_create(struct target *target)
Definition: chibios.c:511
static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
Definition: chibios.c:481
#define GET_CH_KERNEL_MAJOR(coded_version)
Definition: chibios.c:53
#define CH_RLIST_OFFSET
Definition: chibios.c:129
#define CHIBIOS_THREAD_NAME_STR_SIZE
Definition: chibios.c:70
static struct chibios_params chibios_params_list[]
Definition: chibios.c:79
static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
Definition: chibios.c:447
static int chibios_update_threads(struct rtos *rtos)
Definition: chibios.c:256
static bool chibios_detect_rtos(struct target *target)
Definition: chibios.c:492
static const char *const chibios_thread_states[]
ChibiOS thread states.
Definition: chibios.c:60
#define GET_CH_KERNEL_PATCH(coded_version)
Definition: chibios.c:55
const struct rtos_type chibios_rtos
Definition: chibios.c:99
chibios_symbol_values
Definition: chibios.c:115
@ CHIBIOS_VAL_RLIST
Definition: chibios.c:116
@ CHIBIOS_VAL_CH
Definition: chibios.c:117
@ CHIBIOS_VAL_CH_DEBUG
Definition: chibios.c:118
static int chibios_update_memory_signature(struct rtos *rtos)
Definition: chibios.c:131
static struct symbol_table_elem chibios_symbol_list[]
Definition: chibios.c:121
#define FPU_CPACR
Definition: cortex_m.h:112
The JTAG interface can be implemented with a software or hardware fifo.
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
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_chibios_arm_v7m_stacking_w_fpu
const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking
ChibiOS/RT memory signature record.
Definition: chibios.c:30
uint8_t cf_off_refs
Offset of p_refs field.
Definition: chibios.c:47
uint8_t ch_size
Size of this structure.
Definition: chibios.c:33
uint8_t cf_off_older
Offset of p_older field.
Definition: chibios.c:41
uint8_t ch_version[2]
Encoded ChibiOS/RT version.
Definition: chibios.c:34
uint8_t cf_off_flags
Offset of p_flags field.
Definition: chibios.c:46
uint8_t ch_threadsize
Size of a Thread struct.
Definition: chibios.c:37
uint8_t cf_off_name
Offset of p_name field.
Definition: chibios.c:42
uint8_t cf_off_prio
Offset of p_prio field.
Definition: chibios.c:38
uint8_t cf_off_ctx
Offset of p_ctx field.
Definition: chibios.c:39
uint8_t cf_off_stklimit
Offset of p_stklimit field.
Definition: chibios.c:43
uint8_t ch_zero
Must be zero.
Definition: chibios.c:32
uint8_t cf_off_time
Offset of p_time field.
Definition: chibios.c:50
char ch_identifier[4]
Always set to "main".
Definition: chibios.c:31
uint8_t cf_off_newer
Offset of p_newer field.
Definition: chibios.c:40
uint8_t cf_off_preempt
Offset of p_preempt field.
Definition: chibios.c:48
uint8_t ch_ptrsize
Size of a pointer.
Definition: chibios.c:35
uint8_t ch_timesize
Size of a systime_t.
Definition: chibios.c:36
uint8_t cf_off_state
Offset of p_state field.
Definition: chibios.c:45
struct chibios_chdebug * signature
Definition: chibios.c:75
const struct rtos_register_stacking * stacking_info
Definition: chibios.c:76
const char * target_name
Definition: chibios.c:73
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_u32(struct target *target, target_addr_t address, uint32_t *value)
Definition: target.c:2550
uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer)
Definition: target.c:334
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