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