1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2012 by Matthias Blaicher *
5 * Matthias Blaicher - matthias@blaicher.com *
7 * Copyright (C) 2011 by Broadcom Corporation *
8 * Evan Hunter - ehunter@broadcom.com *
9 ***************************************************************************/
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"
22 #include "helper/log.h"
23 #include "helper/types.h"
24 #include "rtos_chibios_stackings.h"
27 * @brief ChibiOS/RT memory signature record.
29 * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
31 struct chibios_chdebug
{
32 char ch_identifier
[4]; /**< @brief Always set to "main". */
33 uint8_t ch_zero
; /**< @brief Must be zero. */
34 uint8_t ch_size
; /**< @brief Size of this structure. */
35 uint16_t ch_version
; /**< @brief Encoded ChibiOS/RT version. */
36 uint8_t ch_ptrsize
; /**< @brief Size of a pointer. */
37 uint8_t ch_timesize
; /**< @brief Size of a @p systime_t. */
38 uint8_t ch_threadsize
; /**< @brief Size of a @p Thread struct. */
39 uint8_t cf_off_prio
; /**< @brief Offset of @p p_prio field. */
40 uint8_t cf_off_ctx
; /**< @brief Offset of @p p_ctx field. */
41 uint8_t cf_off_newer
; /**< @brief Offset of @p p_newer field. */
42 uint8_t cf_off_older
; /**< @brief Offset of @p p_older field. */
43 uint8_t cf_off_name
; /**< @brief Offset of @p p_name field. */
44 uint8_t cf_off_stklimit
; /**< @brief Offset of @p p_stklimit
46 uint8_t cf_off_state
; /**< @brief Offset of @p p_state field. */
47 uint8_t cf_off_flags
; /**< @brief Offset of @p p_flags field. */
48 uint8_t cf_off_refs
; /**< @brief Offset of @p p_refs field. */
49 uint8_t cf_off_preempt
; /**< @brief Offset of @p p_preempt
51 uint8_t cf_off_time
; /**< @brief Offset of @p p_time field. */
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)
59 * @brief ChibiOS thread states.
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"
66 #define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states)
68 /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
69 * chars ought to be enough.
71 #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
73 struct chibios_params
{
74 const char *target_name
;
76 struct chibios_chdebug
*signature
;
77 const struct rtos_register_stacking
*stacking_info
;
80 static struct chibios_params chibios_params_list
[] = {
82 "cortex_m", /* target_name */
84 NULL
, /* stacking_info */
87 "hla_target", /* target_name */
89 NULL
, /* stacking_info */
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
[]);
100 struct rtos_type chibios_rtos
= {
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
,
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.
116 enum chibios_symbol_values
{
117 CHIBIOS_VAL_RLIST
= 0,
119 CHIBIOS_VAL_CH_DEBUG
= 2
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 */
129 /* Offset of the rlist structure within the system data structure (ch) */
130 #define CH_RLIST_OFFSET 0x00
132 static int chibios_update_memory_signature(struct rtos
*rtos
)
135 struct chibios_params
*param
;
136 struct chibios_chdebug
*signature
;
138 param
= (struct chibios_params
*) rtos
->rtos_specific_params
;
140 /* Free existing memory description.*/
141 free(param
->signature
);
142 param
->signature
= NULL
;
144 signature
= malloc(sizeof(*signature
));
146 LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
150 retval
= target_read_buffer(rtos
->target
,
151 rtos
->symbols
[CHIBIOS_VAL_CH_DEBUG
].address
,
153 (uint8_t *) signature
);
154 if (retval
!= ERROR_OK
) {
155 LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
159 if (strncmp(signature
->ch_identifier
, "main", 4) != 0) {
160 LOG_ERROR("Memory signature identifier does not contain magic bytes.");
164 if (signature
->ch_size
< sizeof(*signature
)) {
165 LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
170 if (signature
->ch_size
> sizeof(*signature
)) {
171 LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
172 " expected. Assuming compatibility...");
175 /* Convert endianness of version field */
176 const uint8_t *versiontarget
= (const uint8_t *)
177 &signature
->ch_version
;
178 signature
->ch_version
= rtos
->target
->endianness
== TARGET_LITTLE_ENDIAN
?
179 le_to_h_u32(versiontarget
) : be_to_h_u32(versiontarget
);
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
));
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!");
195 param
->signature
= signature
;
199 /* Error reading the ChibiOS memory structure */
201 param
->signature
= 0;
206 static int chibios_update_stacking(struct rtos
*rtos
)
208 /* Sometimes the stacking can not be determined only by looking at the
209 * target name but only a runtime.
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.
214 * Terminating which stacking is used is target depending.
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.
227 if (!rtos
->rtos_specific_params
)
230 struct chibios_params
*param
;
231 param
= (struct chibios_params
*) rtos
->rtos_specific_params
;
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 */
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");
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.");
250 param
->stacking_info
= &rtos_chibios_arm_v7m_stacking_w_fpu
;
255 /* Found ARM v7m target with no or disabled FPU */
256 param
->stacking_info
= &rtos_chibios_arm_v7m_stacking
;
263 static int chibios_update_threads(struct rtos
*rtos
)
266 const struct chibios_params
*param
;
270 if (!rtos
->rtos_specific_params
)
273 if (!rtos
->symbols
) {
274 LOG_ERROR("No symbols for ChibiOS");
278 param
= (const struct chibios_params
*) rtos
->rtos_specific_params
;
279 /* Update the memory signature saved in the target memory */
280 if (!param
->signature
) {
281 retval
= chibios_update_memory_signature(rtos
);
282 if (retval
!= ERROR_OK
) {
283 LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
288 /* wipe out previous thread details if any */
289 rtos_free_threadlist(rtos
);
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
294 const uint32_t rlist
= rtos
->symbols
[CHIBIOS_VAL_RLIST
].address
?
295 rtos
->symbols
[CHIBIOS_VAL_RLIST
].address
:
296 rtos
->symbols
[CHIBIOS_VAL_CH
].address
+ CH_RLIST_OFFSET
/* ChibiOS3 */;
297 const struct chibios_chdebug
*signature
= param
->signature
;
305 retval
= target_read_u32(rtos
->target
,
306 current
+ signature
->cf_off_newer
, ¤t
);
307 if (retval
!= ERROR_OK
) {
308 LOG_ERROR("Could not read next ChibiOS thread");
311 /* Could be NULL if the kernel is not initialized yet or if the
312 * registry is corrupted. */
314 LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
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");
328 /* Check for full iteration of the linked list. */
329 if (current
== rlist
)
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.");
339 const char tmp_thread_name
[] = "Current Execution";
340 const char tmp_thread_extra_info
[] = "No RTOS thread";
342 rtos
->thread_details
= malloc(
343 sizeof(struct thread_detail
));
344 rtos
->thread_details
->threadid
= 1;
345 rtos
->thread_details
->exists
= true;
347 rtos
->thread_details
->extra_info_str
= malloc(
348 sizeof(tmp_thread_extra_info
));
349 strcpy(rtos
->thread_details
->extra_info_str
, tmp_thread_extra_info
);
351 rtos
->thread_details
->thread_name_str
= malloc(
352 sizeof(tmp_thread_name
));
353 strcpy(rtos
->thread_details
->thread_name_str
, tmp_thread_name
);
355 rtos
->current_thread
= 1;
356 rtos
->thread_count
= 1;
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");
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
];
375 retval
= target_read_u32(rtos
->target
,
376 current
+ signature
->cf_off_newer
, ¤t
);
377 if (retval
!= ERROR_OK
) {
378 LOG_ERROR("Could not read next ChibiOS thread");
382 /* Check for full iteration of the linked list. */
383 if (current
== rlist
)
386 /* Save the thread pointer */
387 curr_thrd_details
->threadid
= current
;
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");
397 /* Read the thread name */
398 retval
= target_read_buffer(rtos
->target
, name_ptr
,
399 CHIBIOS_THREAD_NAME_STR_SIZE
,
400 (uint8_t *)&tmp_str
);
401 if (retval
!= ERROR_OK
) {
402 LOG_ERROR("Error reading thread name from ChibiOS target");
405 tmp_str
[CHIBIOS_THREAD_NAME_STR_SIZE
- 1] = '\x00';
407 if (tmp_str
[0] == '\x00')
408 strcpy(tmp_str
, "No Name");
410 curr_thrd_details
->thread_name_str
= malloc(
411 strlen(tmp_str
) + 1);
412 strcpy(curr_thrd_details
->thread_name_str
, tmp_str
);
415 uint8_t thread_state
;
416 const char *state_desc
;
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");
426 if (thread_state
< CHIBIOS_NUM_STATES
)
427 state_desc
= chibios_thread_states
[thread_state
];
429 state_desc
= "Unknown";
431 curr_thrd_details
->extra_info_str
= malloc(strlen(
433 sprintf(curr_thrd_details
->extra_info_str
, "State: %s", state_desc
);
435 curr_thrd_details
->exists
= true;
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
,
445 if (retval
!= ERROR_OK
) {
446 LOG_ERROR("Could not read current Thread from ChibiOS target");
449 rtos
->current_thread
= current_thrd
;
454 static int chibios_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
455 struct rtos_reg
**reg_list
, int *num_regs
)
458 const struct chibios_params
*param
;
459 uint32_t stack_ptr
= 0;
461 if ((!rtos
) || (thread_id
== 0) ||
462 (!rtos
->rtos_specific_params
))
465 param
= (const struct chibios_params
*) rtos
->rtos_specific_params
;
467 if (!param
->signature
)
470 /* Update stacking if it can only be determined from runtime information */
471 if ((param
->stacking_info
== 0) &&
472 (chibios_update_stacking(rtos
) != ERROR_OK
)) {
473 LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos
->target
->type
->name
);
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");
485 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, reg_list
, num_regs
);
488 static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
490 *symbol_list
= malloc(sizeof(chibios_symbol_list
));
495 memcpy(*symbol_list
, chibios_symbol_list
, sizeof(chibios_symbol_list
));
499 static bool chibios_detect_rtos(struct target
*target
)
501 if ((target
->rtos
->symbols
) &&
502 ((target
->rtos
->symbols
[CHIBIOS_VAL_RLIST
].address
!= 0) ||
503 (target
->rtos
->symbols
[CHIBIOS_VAL_CH
].address
!= 0))) {
505 if (target
->rtos
->symbols
[CHIBIOS_VAL_CH_DEBUG
].address
== 0) {
506 LOG_INFO("It looks like the target may be running ChibiOS "
507 "without ch_debug.");
511 /* looks like ChibiOS with memory map enabled.*/
518 static int chibios_create(struct target
*target
)
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) {
522 target
->rtos
->rtos_specific_params
= (void *)&chibios_params_list
[i
];
526 LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
527 "list", target
->type
->name
);