1 /***************************************************************************
2 * Copyright (C) 2012 by Matthias Blaicher *
3 * Matthias Blaicher - matthias@blaicher.com *
5 * Copyright (C) 2011 by Broadcom Corporation *
6 * Evan Hunter - ehunter@broadcom.com *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 ***************************************************************************/
26 #include <helper/time_support.h>
27 #include <jtag/jtag.h>
28 #include "target/target.h"
29 #include "target/target_type.h"
30 #include "target/armv7m.h"
31 #include "target/cortex_m.h"
33 #include "helper/log.h"
34 #include "helper/types.h"
35 #include "rtos_chibios_stackings.h"
38 * @brief ChibiOS/RT memory signature record.
40 * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
42 struct ChibiOS_chdebug
{
43 char ch_identifier
[4]; /**< @brief Always set to "main". */
44 uint8_t ch_zero
; /**< @brief Must be zero. */
45 uint8_t ch_size
; /**< @brief Size of this structure. */
46 uint16_t ch_version
; /**< @brief Encoded ChibiOS/RT version. */
47 uint8_t ch_ptrsize
; /**< @brief Size of a pointer. */
48 uint8_t ch_timesize
; /**< @brief Size of a @p systime_t. */
49 uint8_t ch_threadsize
; /**< @brief Size of a @p Thread struct. */
50 uint8_t cf_off_prio
; /**< @brief Offset of @p p_prio field. */
51 uint8_t cf_off_ctx
; /**< @brief Offset of @p p_ctx field. */
52 uint8_t cf_off_newer
; /**< @brief Offset of @p p_newer field. */
53 uint8_t cf_off_older
; /**< @brief Offset of @p p_older field. */
54 uint8_t cf_off_name
; /**< @brief Offset of @p p_name field. */
55 uint8_t cf_off_stklimit
; /**< @brief Offset of @p p_stklimit
57 uint8_t cf_off_state
; /**< @brief Offset of @p p_state field. */
58 uint8_t cf_off_flags
; /**< @brief Offset of @p p_flags field. */
59 uint8_t cf_off_refs
; /**< @brief Offset of @p p_refs field. */
60 uint8_t cf_off_preempt
; /**< @brief Offset of @p p_preempt
62 uint8_t cf_off_time
; /**< @brief Offset of @p p_time field. */
65 #define GET_CH_KERNEL_MAJOR(codedVersion) ((codedVersion >> 11) & 0x1f)
66 #define GET_CH_KERNEL_MINOR(codedVersion) ((codedVersion >> 6) & 0x1f)
67 #define GET_CH_KERNEL_PATCH(codedVersion) ((codedVersion >> 0) & 0x3f)
70 * @brief ChibiOS thread states.
72 static const char * const ChibiOS_thread_states
[] = {
73 "READY", "CURRENT", "SUSPENDED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING",
74 "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "WTQUEUE",
78 #define CHIBIOS_NUM_STATES (sizeof(ChibiOS_thread_states)/sizeof(char *))
80 /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
81 * chars ought to be enough.
83 #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
85 struct ChibiOS_params
{
86 const char *target_name
;
88 struct ChibiOS_chdebug
*signature
;
89 const struct rtos_register_stacking
*stacking_info
;
92 static struct ChibiOS_params ChibiOS_params_list
[] = {
94 "cortex_m", /* target_name */
96 NULL
, /* stacking_info */
99 "hla_target", /* target_name */
101 NULL
, /* stacking_info */
104 #define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params)))
106 static int ChibiOS_detect_rtos(struct target
*target
);
107 static int ChibiOS_create(struct target
*target
);
108 static int ChibiOS_update_threads(struct rtos
*rtos
);
109 static int ChibiOS_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
);
110 static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[]);
112 struct rtos_type ChibiOS_rtos
= {
115 .detect_rtos
= ChibiOS_detect_rtos
,
116 .create
= ChibiOS_create
,
117 .update_threads
= ChibiOS_update_threads
,
118 .get_thread_reg_list
= ChibiOS_get_thread_reg_list
,
119 .get_symbol_list_to_lookup
= ChibiOS_get_symbol_list_to_lookup
,
123 /* In ChibiOS/RT 3.0 the rlist structure has become part of a system
124 * data structure ch. We declare both symbols as optional and later
125 * use whatever is available.
128 enum ChibiOS_symbol_values
{
129 ChibiOS_VAL_rlist
= 0,
131 ChibiOS_VAL_ch_debug
= 2,
132 ChibiOS_VAL_chSysInit
= 3
135 static symbol_table_elem_t ChibiOS_symbol_list
[] = {
136 { "rlist", 0, true}, /* Thread ready list */
137 { "ch", 0, true}, /* System data structure */
138 { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */
139 { "chSysInit", 0, false}, /* Necessary part of API, used for ChibiOS detection */
143 /* Offset of the rlist structure within the system data structure (ch) */
144 #define CH_RLIST_OFFSET 0x00
146 static int ChibiOS_update_memory_signature(struct rtos
*rtos
)
149 struct ChibiOS_params
*param
;
150 struct ChibiOS_chdebug
*signature
;
152 param
= (struct ChibiOS_params
*) rtos
->rtos_specific_params
;
154 /* Free existing memory description.*/
155 if (param
->signature
) {
156 free(param
->signature
);
157 param
->signature
= 0;
160 signature
= malloc(sizeof(*signature
));
162 LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
166 retval
= target_read_buffer(rtos
->target
,
167 rtos
->symbols
[ChibiOS_VAL_ch_debug
].address
,
169 (uint8_t *) signature
);
170 if (retval
!= ERROR_OK
) {
171 LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
175 if (strncmp(signature
->ch_identifier
, "main", 4) != 0) {
176 LOG_ERROR("Memory signature identifier does not contain magic bytes.");
180 if (signature
->ch_size
< sizeof(*signature
)) {
181 LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
186 if (signature
->ch_size
> sizeof(*signature
)) {
187 LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
188 " expected. Assuming compatibility...");
191 /* Convert endianness of version field */
192 const uint8_t *versionTarget
= (const uint8_t *)
193 &signature
->ch_version
;
194 signature
->ch_version
= rtos
->target
->endianness
== TARGET_LITTLE_ENDIAN
?
195 le_to_h_u32(versionTarget
) : be_to_h_u32(versionTarget
);
197 const uint16_t ch_version
= signature
->ch_version
;
198 LOG_INFO("Successfully loaded memory map of ChibiOS/RT target "
199 "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version
),
200 GET_CH_KERNEL_MINOR(ch_version
), GET_CH_KERNEL_PATCH(ch_version
));
202 /* Currently, we have the inherent assumption that all address pointers
203 * are 32 bit wide. */
204 if (signature
->ch_ptrsize
!= sizeof(uint32_t)) {
205 LOG_ERROR("ChibiOS/RT target memory signature claims an address"
206 "width unequal to 32 bits!");
211 param
->signature
= signature
;
215 /* Error reading the ChibiOS memory structure */
217 param
->signature
= 0;
222 static int ChibiOS_update_stacking(struct rtos
*rtos
)
224 /* Sometimes the stacking can not be determined only by looking at the
225 * target name but only a runtime.
227 * For example, this is the case for Cortex-M4 targets and ChibiOS which
228 * only stack the FPU registers if it is enabled during ChibiOS build.
230 * Terminating which stacking is used is target depending.
233 * - Once ChibiOS is actually initialized, the stacking is fixed.
234 * - During startup code, the FPU might not be initialized and the
235 * detection might fail.
236 * - Since no threads are running during startup, the problem is solved
237 * by delaying stacking detection until there are more threads
238 * available than the current execution. In which case
239 * ChibiOS_get_thread_reg_list is called.
243 if (!rtos
->rtos_specific_params
)
246 struct ChibiOS_params
*param
;
247 param
= (struct ChibiOS_params
*) rtos
->rtos_specific_params
;
249 /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */
250 struct armv7m_common
*armv7m_target
= target_to_armv7m(rtos
->target
);
251 if (is_armv7m(armv7m_target
)) {
252 if (armv7m_target
->fp_feature
== FPv4_SP
) {
253 /* Found ARM v7m target which includes a FPU */
256 retval
= target_read_u32(rtos
->target
, FPU_CPACR
, &cpacr
);
257 if (retval
!= ERROR_OK
) {
258 LOG_ERROR("Could not read CPACR register to check FPU state");
262 /* Check if CP10 and CP11 are set to full access.
263 * In ChibiOS this is done in ResetHandler() in crt0.c */
264 if (cpacr
& 0x00F00000) {
265 LOG_DEBUG("Enabled FPU detected.");
266 param
->stacking_info
= &rtos_chibios_arm_v7m_stacking_w_fpu
;
271 /* Found ARM v7m target with no or disabled FPU */
272 param
->stacking_info
= &rtos_chibios_arm_v7m_stacking
;
279 static int ChibiOS_update_threads(struct rtos
*rtos
)
282 const struct ChibiOS_params
*param
;
286 if (!rtos
->rtos_specific_params
)
289 if (!rtos
->symbols
) {
290 LOG_ERROR("No symbols for ChibiOS");
294 param
= (const struct ChibiOS_params
*) rtos
->rtos_specific_params
;
295 /* Update the memory signature saved in the target memory */
296 if (!param
->signature
) {
297 retval
= ChibiOS_update_memory_signature(rtos
);
298 if (retval
!= ERROR_OK
) {
299 LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
304 /* wipe out previous thread details if any */
305 rtos_free_threadlist(rtos
);
307 /* ChibiOS does not save the current thread count. We have to first
308 * parse the double linked thread list to check for errors and the number of
310 const uint32_t rlist
= rtos
->symbols
[ChibiOS_VAL_rlist
].address
?
311 rtos
->symbols
[ChibiOS_VAL_rlist
].address
:
312 rtos
->symbols
[ChibiOS_VAL_ch
].address
+ CH_RLIST_OFFSET
/* ChibiOS3 */;
313 const struct ChibiOS_chdebug
*signature
= param
->signature
;
321 retval
= target_read_u32(rtos
->target
,
322 current
+ signature
->cf_off_newer
, ¤t
);
323 if (retval
!= ERROR_OK
) {
324 LOG_ERROR("Could not read next ChibiOS thread");
327 /* Could be NULL if the kernel is not initialized yet or if the
328 * registry is corrupted. */
330 LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
335 /* Fetch previous thread in the list as a integrity check. */
336 retval
= target_read_u32(rtos
->target
,
337 current
+ signature
->cf_off_older
, &older
);
338 if ((retval
!= ERROR_OK
) || (older
== 0) || (older
!= previous
)) {
339 LOG_ERROR("ChibiOS registry integrity check failed, "
340 "double linked list violation");
344 /* Check for full iteration of the linked list. */
345 if (current
== rlist
)
351 /* No RTOS, there is always at least the current execution, though */
352 LOG_INFO("Only showing current execution because of a broken "
353 "ChibiOS thread registry.");
355 const char tmp_thread_name
[] = "Current Execution";
356 const char tmp_thread_extra_info
[] = "No RTOS thread";
358 rtos
->thread_details
= malloc(
359 sizeof(struct thread_detail
));
360 rtos
->thread_details
->threadid
= 1;
361 rtos
->thread_details
->exists
= true;
362 rtos
->thread_details
->display_str
= NULL
;
364 rtos
->thread_details
->extra_info_str
= malloc(
365 sizeof(tmp_thread_extra_info
));
366 strcpy(rtos
->thread_details
->extra_info_str
, tmp_thread_extra_info
);
368 rtos
->thread_details
->thread_name_str
= malloc(
369 sizeof(tmp_thread_name
));
370 strcpy(rtos
->thread_details
->thread_name_str
, tmp_thread_name
);
372 rtos
->current_thread
= 1;
373 rtos
->thread_count
= 1;
377 /* create space for new thread details */
378 rtos
->thread_details
= malloc(
379 sizeof(struct thread_detail
) * tasks_found
);
380 if (!rtos
->thread_details
) {
381 LOG_ERROR("Could not allocate space for thread details");
385 rtos
->thread_count
= tasks_found
;
386 /* Loop through linked list. */
387 struct thread_detail
*curr_thrd_details
= rtos
->thread_details
;
388 while (curr_thrd_details
< rtos
->thread_details
+ tasks_found
) {
389 uint32_t name_ptr
= 0;
390 char tmp_str
[CHIBIOS_THREAD_NAME_STR_SIZE
];
392 retval
= target_read_u32(rtos
->target
,
393 current
+ signature
->cf_off_newer
, ¤t
);
394 if (retval
!= ERROR_OK
) {
395 LOG_ERROR("Could not read next ChibiOS thread");
399 /* Check for full iteration of the linked list. */
400 if (current
== rlist
)
403 /* Save the thread pointer */
404 curr_thrd_details
->threadid
= current
;
406 /* read the name pointer */
407 retval
= target_read_u32(rtos
->target
,
408 current
+ signature
->cf_off_name
, &name_ptr
);
409 if (retval
!= ERROR_OK
) {
410 LOG_ERROR("Could not read ChibiOS thread name pointer from target");
414 /* Read the thread name */
415 retval
= target_read_buffer(rtos
->target
, name_ptr
,
416 CHIBIOS_THREAD_NAME_STR_SIZE
,
417 (uint8_t *)&tmp_str
);
418 if (retval
!= ERROR_OK
) {
419 LOG_ERROR("Error reading thread name from ChibiOS target");
422 tmp_str
[CHIBIOS_THREAD_NAME_STR_SIZE
- 1] = '\x00';
424 if (tmp_str
[0] == '\x00')
425 strcpy(tmp_str
, "No Name");
427 curr_thrd_details
->thread_name_str
= malloc(
428 strlen(tmp_str
) + 1);
429 strcpy(curr_thrd_details
->thread_name_str
, tmp_str
);
433 const char *state_desc
;
435 retval
= target_read_u8(rtos
->target
,
436 current
+ signature
->cf_off_state
, &threadState
);
437 if (retval
!= ERROR_OK
) {
438 LOG_ERROR("Error reading thread state from ChibiOS target");
443 if (threadState
< CHIBIOS_NUM_STATES
)
444 state_desc
= ChibiOS_thread_states
[threadState
];
446 state_desc
= "Unknown state";
448 curr_thrd_details
->extra_info_str
= malloc(strlen(
450 strcpy(curr_thrd_details
->extra_info_str
, state_desc
);
452 curr_thrd_details
->exists
= true;
453 curr_thrd_details
->display_str
= NULL
;
458 uint32_t current_thrd
;
459 /* NOTE: By design, cf_off_name equals readylist_current_offset */
460 retval
= target_read_u32(rtos
->target
,
461 rlist
+ signature
->cf_off_name
,
463 if (retval
!= ERROR_OK
) {
464 LOG_ERROR("Could not read current Thread from ChibiOS target");
467 rtos
->current_thread
= current_thrd
;
472 static int ChibiOS_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
475 const struct ChibiOS_params
*param
;
476 uint32_t stack_ptr
= 0;
478 *hex_reg_list
= NULL
;
479 if ((rtos
== NULL
) || (thread_id
== 0) ||
480 (rtos
->rtos_specific_params
== NULL
))
483 param
= (const struct ChibiOS_params
*) rtos
->rtos_specific_params
;
485 if (!param
->signature
)
488 /* Update stacking if it can only be determined from runtime information */
489 if ((param
->stacking_info
== 0) &&
490 (ChibiOS_update_stacking(rtos
) != ERROR_OK
)) {
491 LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos
->target
->type
->name
);
495 /* Read the stack pointer */
496 retval
= target_read_u32(rtos
->target
,
497 thread_id
+ param
->signature
->cf_off_ctx
, &stack_ptr
);
498 if (retval
!= ERROR_OK
) {
499 LOG_ERROR("Error reading stack frame from ChibiOS thread");
503 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, hex_reg_list
);
506 static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
508 *symbol_list
= malloc(sizeof(ChibiOS_symbol_list
));
510 if (*symbol_list
== NULL
)
513 memcpy(*symbol_list
, ChibiOS_symbol_list
, sizeof(ChibiOS_symbol_list
));
517 static int ChibiOS_detect_rtos(struct target
*target
)
519 if ((target
->rtos
->symbols
!= NULL
) &&
520 ((target
->rtos
->symbols
[ChibiOS_VAL_rlist
].address
!= 0) ||
521 (target
->rtos
->symbols
[ChibiOS_VAL_ch
].address
!= 0)) &&
522 (target
->rtos
->symbols
[ChibiOS_VAL_chSysInit
].address
!= 0)) {
524 if (target
->rtos
->symbols
[ChibiOS_VAL_ch_debug
].address
== 0) {
525 LOG_INFO("It looks like the target is running ChibiOS without "
530 /* looks like ChibiOS with memory map enabled.*/
537 static int ChibiOS_create(struct target
*target
)
540 while ((i
< CHIBIOS_NUM_PARAMS
) &&
541 (0 != strcmp(ChibiOS_params_list
[i
].target_name
, target
->type
->name
))) {
544 if (i
>= CHIBIOS_NUM_PARAMS
) {
545 LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
546 "list", target
->type
->name
);
550 target
->rtos
->rtos_specific_params
= (void *) &ChibiOS_params_list
[i
];