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, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
28 #include <helper/time_support.h>
29 #include <jtag/jtag.h>
30 #include "target/target.h"
31 #include "target/target_type.h"
33 #include "helper/log.h"
34 #include "helper/types.h"
35 #include "rtos_chibios_stackings.h"
39 * @brief ChibiOS/RT memory signature record.
41 * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
43 struct ChibiOS_chdebug
{
44 char ch_identifier
[4]; /**< @brief Always set to "main". */
45 uint8_t ch_zero
; /**< @brief Must be zero. */
46 uint8_t ch_size
; /**< @brief Size of this structure. */
47 uint16_t ch_version
; /**< @brief Encoded ChibiOS/RT version. */
48 uint8_t ch_ptrsize
; /**< @brief Size of a pointer. */
49 uint8_t ch_timesize
; /**< @brief Size of a @p systime_t. */
50 uint8_t ch_threadsize
; /**< @brief Size of a @p Thread struct. */
51 uint8_t cf_off_prio
; /**< @brief Offset of @p p_prio field. */
52 uint8_t cf_off_ctx
; /**< @brief Offset of @p p_ctx field. */
53 uint8_t cf_off_newer
; /**< @brief Offset of @p p_newer field. */
54 uint8_t cf_off_older
; /**< @brief Offset of @p p_older field. */
55 uint8_t cf_off_name
; /**< @brief Offset of @p p_name field. */
56 uint8_t cf_off_stklimit
; /**< @brief Offset of @p p_stklimit
58 uint8_t cf_off_state
; /**< @brief Offset of @p p_state field. */
59 uint8_t cf_off_flags
; /**< @brief Offset of @p p_flags field. */
60 uint8_t cf_off_refs
; /**< @brief Offset of @p p_refs field. */
61 uint8_t cf_off_preempt
; /**< @brief Offset of @p p_preempt
63 uint8_t cf_off_time
; /**< @brief Offset of @p p_time field. */
66 #define GET_CH_KERNEL_MAJOR(codedVersion) ((codedVersion >> 11) & 0x1f)
67 #define GET_CH_KERNEL_MINOR(codedVersion) ((codedVersion >> 6) & 0x1f)
68 #define GET_CH_KERNEL_PATCH(codedVersion) ((codedVersion >> 0) & 0x3f)
71 * @brief ChibiOS thread states.
73 const char *ChibiOS_thread_states
[] = {
74 "READY", "CURRENT", "SUSPENDED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING",
75 "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "WTQUEUE",
79 #define CHIBIOS_NUM_STATES (sizeof(ChibiOS_thread_states)/sizeof(char *))
81 /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
82 * chars ought to be enough.
84 #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
86 struct ChibiOS_params
{
87 const char *target_name
;
89 struct ChibiOS_chdebug
*signature
;
90 const struct rtos_register_stacking
*stacking_info
;
93 struct ChibiOS_params ChibiOS_params_list
[] = {
95 "cortex_m3", /* target_name */
97 &rtos_chibios_arm_v7m_stacking
, /* stacking_info */
100 "stm32_stlink", /* target_name */
102 &rtos_chibios_arm_v7m_stacking
, /* stacking_info */
105 #define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params)))
107 static int ChibiOS_detect_rtos(struct target
*target
);
108 static int ChibiOS_create(struct target
*target
);
109 static int ChibiOS_update_threads(struct rtos
*rtos
);
110 static int ChibiOS_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
);
111 static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[]);
113 struct rtos_type ChibiOS_rtos
= {
116 .detect_rtos
= ChibiOS_detect_rtos
,
117 .create
= ChibiOS_create
,
118 .update_threads
= ChibiOS_update_threads
,
119 .get_thread_reg_list
= ChibiOS_get_thread_reg_list
,
120 .get_symbol_list_to_lookup
= ChibiOS_get_symbol_list_to_lookup
,
123 enum ChibiOS_symbol_values
{
124 ChibiOS_VAL_rlist
= 0,
125 ChibiOS_VAL_ch_debug
= 1,
126 ChibiOS_VAL_chSysInit
= 2
129 static char *ChibiOS_symbol_list
[] = {
130 "rlist", /* Thread ready list*/
131 "ch_debug", /* Memory Signatur containing offsets of fields in rlist*/
132 "chSysInit", /* Necessary part of API, used for ChibiOS detection*/
136 static int ChibiOS_update_memory_signature(struct rtos
*rtos
)
139 struct ChibiOS_params
*param
;
140 struct ChibiOS_chdebug
*signature
;
142 param
= (struct ChibiOS_params
*) rtos
->rtos_specific_params
;
144 /* Free existing memory description.*/
145 if (param
->signature
) {
146 free(param
->signature
);
147 param
->signature
= 0;
150 signature
= malloc(sizeof(*signature
));
152 LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
156 retval
= target_read_buffer(rtos
->target
,
157 rtos
->symbols
[ChibiOS_VAL_ch_debug
].address
,
159 (uint8_t *) signature
);
160 if (retval
!= ERROR_OK
) {
161 LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
165 if (strncmp(signature
->ch_identifier
, "main", 4) != 0) {
166 LOG_ERROR("Memory signature identifier does not contain magic bytes.");
170 if (signature
->ch_size
< sizeof(*signature
)) {
171 LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
176 if (signature
->ch_size
> sizeof(*signature
)) {
177 LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
178 " expected. Assuming compatibility...");
181 /* Convert endianness of version field */
182 const uint8_t *versionTarget
= (const uint8_t *)
183 &signature
->ch_version
;
184 signature
->ch_version
= rtos
->target
->endianness
== TARGET_LITTLE_ENDIAN
?
185 le_to_h_u32(versionTarget
) : be_to_h_u32(versionTarget
);
187 const uint16_t ch_version
= signature
->ch_version
;
188 LOG_INFO("Successfully loaded memory map of ChibiOS/RT target "
189 "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version
),
190 GET_CH_KERNEL_MINOR(ch_version
), GET_CH_KERNEL_PATCH(ch_version
));
192 param
->signature
= signature
;
196 /* Error reading the ChibiOS memory structure */
198 param
->signature
= 0;
203 static int ChibiOS_update_stacking(struct rtos
*rtos
)
205 /* Sometimes the stacking can not be determined only by looking at the
206 * target name but only a runtime.
208 * For example, this is the case for cortex-m4 targets and ChibiOS which
209 * only stack the FPU registers if it is enabled during ChibiOS build.
211 * Terminating which stacking is used is target depending.
214 * - Once ChibiOS is actually initialized, the stacking is fixed.
215 * - During startup code, the FPU might not be initialized and the
216 * detection might fail.
217 * - Since no threads are running during startup, the problem is solved
218 * by delaying stacking detection until there are more threads
219 * available than the current execution. In which case
220 * ChibiOS_get_thread_reg_list is called.
223 /* TODO: Add actual detection, currently it will not work with FPU enabled.*/
227 static int ChibiOS_update_threads(struct rtos
*rtos
)
230 const struct ChibiOS_params
*param
;
234 if (!rtos
->rtos_specific_params
)
237 if (!rtos
->symbols
) {
238 LOG_ERROR("No symbols for ChibiOS");
242 param
= (const struct ChibiOS_params
*) rtos
->rtos_specific_params
;
243 /* Update the memory signature saved in the target memory */
244 if (!param
->signature
) {
245 retval
= ChibiOS_update_memory_signature(rtos
);
246 if (retval
!= ERROR_OK
) {
247 LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
252 /* wipe out previous thread details if any */
254 if (rtos
->thread_details
) {
255 for (j
= 0; j
< rtos
->thread_count
; j
++) {
256 struct thread_detail
*current_thread
= &rtos
->thread_details
[j
];
257 if (current_thread
->display_str
!= NULL
)
258 free(current_thread
->display_str
);
259 if (current_thread
->thread_name_str
!= NULL
)
260 free(current_thread
->thread_name_str
);
261 if (current_thread
->extra_info_str
!= NULL
)
262 free(current_thread
->extra_info_str
);
264 free(rtos
->thread_details
);
265 rtos
->thread_details
= NULL
;
266 rtos
->thread_count
= 0;
268 /* ChibiOS does not save the current thread count. We have to first
269 * parse the double linked thread list to check for errors and the number of
276 retval
= target_read_buffer(rtos
->target
,
277 rtos
->symbols
[ChibiOS_VAL_rlist
].address
,
278 param
->signature
->ch_ptrsize
,
280 if (retval
!= ERROR_OK
) {
281 LOG_ERROR("Could not read ChibiOS ReadyList from target");
287 retval
= target_read_buffer(rtos
->target
,
288 current
+ param
->signature
->cf_off_newer
,
289 param
->signature
->ch_ptrsize
,
290 (uint8_t *)¤t
);
291 if (retval
!= ERROR_OK
) {
292 LOG_ERROR("Could not read next ChibiOS thread");
295 /* Could be NULL if the kernel is not initialized yet or if the
296 * registry is corrupted. */
298 LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
303 /* Fetch previous thread in the list as a integrity check. */
304 retval
= target_read_buffer(rtos
->target
,
305 current
+ param
->signature
->cf_off_older
,
306 param
->signature
->ch_ptrsize
,
308 if ((retval
!= ERROR_OK
) || (older
== 0) || (older
!= previous
)) {
309 LOG_ERROR("ChibiOS registry integrity check failed, "
310 "double linked list violation");
314 /* Check for full iteration of the linked list. */
315 if (current
== rlist
)
321 /* No RTOS, there is always at least the current execution, though */
322 LOG_INFO("Only showing current execution because of a broken "
323 "ChibiOS thread registry.");
325 const char tmp_thread_name
[] = "Current Execution";
326 const char tmp_thread_extra_info
[] = "No RTOS thread";
328 rtos
->thread_details
= (struct thread_detail
*) malloc(
329 sizeof(struct thread_detail
));
330 rtos
->thread_details
->threadid
= 1;
331 rtos
->thread_details
->exists
= true;
332 rtos
->thread_details
->display_str
= NULL
;
334 rtos
->thread_details
->extra_info_str
= (char *) malloc(
335 sizeof(tmp_thread_extra_info
));
336 strcpy(rtos
->thread_details
->extra_info_str
, tmp_thread_extra_info
);
338 rtos
->thread_details
->thread_name_str
= (char *) malloc(
339 sizeof(tmp_thread_name
));
340 strcpy(rtos
->thread_details
->thread_name_str
, tmp_thread_name
);
342 rtos
->current_thread
= 1;
343 rtos
->thread_count
= 1;
347 /* create space for new thread details */
348 rtos
->thread_details
= (struct thread_detail
*) malloc(
349 sizeof(struct thread_detail
) * tasks_found
);
350 if (!rtos
->thread_details
) {
351 LOG_ERROR("Could not allocate space for thread details");
355 rtos
->thread_count
= tasks_found
;
356 /* Loop through linked list. */
357 struct thread_detail
*curr_thrd_details
= rtos
->thread_details
;
358 while (curr_thrd_details
< rtos
->thread_details
+ tasks_found
) {
359 uint32_t name_ptr
= 0;
360 char tmp_str
[CHIBIOS_THREAD_NAME_STR_SIZE
];
362 retval
= target_read_buffer(rtos
->target
,
363 current
+ param
->signature
->cf_off_newer
,
364 param
->signature
->ch_ptrsize
,
365 (uint8_t *)¤t
);
366 if (retval
!= ERROR_OK
) {
367 LOG_ERROR("Could not read next ChibiOS thread");
371 /* Check for full iteration of the linked list. */
372 if (current
== rlist
)
375 /* Save the thread pointer */
376 curr_thrd_details
->threadid
= current
;
378 /* read the name pointer */
379 retval
= target_read_buffer(rtos
->target
,
380 current
+ param
->signature
->cf_off_name
,
381 param
->signature
->ch_ptrsize
,
382 (uint8_t *)&name_ptr
);
383 if (retval
!= ERROR_OK
) {
384 LOG_ERROR("Could not read ChibiOS thread name pointer from target");
388 /* Read the thread name */
389 retval
= target_read_buffer(rtos
->target
, name_ptr
,
390 CHIBIOS_THREAD_NAME_STR_SIZE
,
391 (uint8_t *)&tmp_str
);
392 if (retval
!= ERROR_OK
) {
393 LOG_ERROR("Error reading thread name from ChibiOS target");
396 tmp_str
[CHIBIOS_THREAD_NAME_STR_SIZE
- 1] = '\x00';
398 if (tmp_str
[0] == '\x00')
399 strcpy(tmp_str
, "No Name");
401 curr_thrd_details
->thread_name_str
= (char *)malloc(
402 strlen(tmp_str
) + 1);
403 strcpy(curr_thrd_details
->thread_name_str
, tmp_str
);
407 const char *state_desc
;
409 retval
= target_read_buffer(rtos
->target
,
410 current
+ param
->signature
->cf_off_state
,
412 if (retval
!= ERROR_OK
) {
413 LOG_ERROR("Error reading thread state from ChibiOS target");
418 if (threadState
< CHIBIOS_NUM_STATES
)
419 state_desc
= ChibiOS_thread_states
[threadState
];
421 state_desc
= "Unknown state";
423 curr_thrd_details
->extra_info_str
= (char *)malloc(strlen(
425 strcpy(curr_thrd_details
->extra_info_str
, state_desc
);
427 curr_thrd_details
->exists
= true;
428 curr_thrd_details
->display_str
= NULL
;
432 /* NOTE: By design, cf_off_name equals readylist_current_offset */
433 retval
= target_read_buffer(rtos
->target
,
434 rlist
+ param
->signature
->cf_off_name
,
435 param
->signature
->ch_ptrsize
,
436 (uint8_t *)&rtos
->current_thread
);
437 if (retval
!= ERROR_OK
) {
438 LOG_ERROR("Could not read current Thread from ChibiOS target");
445 static int ChibiOS_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
, char **hex_reg_list
)
448 const struct ChibiOS_params
*param
;
449 int64_t stack_ptr
= 0;
451 *hex_reg_list
= NULL
;
452 if ((rtos
== NULL
) || (thread_id
== 0) ||
453 (rtos
->rtos_specific_params
== NULL
))
456 param
= (const struct ChibiOS_params
*) rtos
->rtos_specific_params
;
458 if (!param
->signature
)
461 /* Update stacking if it can only be determined from runtime information */
462 if ((param
->stacking_info
== 0) &&
463 (ChibiOS_update_stacking(rtos
) != ERROR_OK
)) {
464 LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos
->target
->type
->name
);
468 /* Read the stack pointer */
469 retval
= target_read_buffer(rtos
->target
,
470 thread_id
+ param
->signature
->cf_off_ctx
,
471 param
->signature
->ch_ptrsize
,
472 (uint8_t *)&stack_ptr
);
473 if (retval
!= ERROR_OK
) {
474 LOG_ERROR("Error reading stack frame from ChibiOS thread");
478 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info
, stack_ptr
, hex_reg_list
);
481 static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
484 *symbol_list
= (symbol_table_elem_t
*) malloc(
485 sizeof(symbol_table_elem_t
) * ARRAY_SIZE(ChibiOS_symbol_list
));
487 for (i
= 0; i
< ARRAY_SIZE(ChibiOS_symbol_list
); i
++)
488 (*symbol_list
)[i
].symbol_name
= ChibiOS_symbol_list
[i
];
493 static int ChibiOS_detect_rtos(struct target
*target
)
495 if ((target
->rtos
->symbols
!= NULL
) &&
496 (target
->rtos
->symbols
[ChibiOS_VAL_rlist
].address
!= 0) &&
497 (target
->rtos
->symbols
[ChibiOS_VAL_chSysInit
].address
!= 0)) {
499 if (target
->rtos
->symbols
[ChibiOS_VAL_ch_debug
].address
== 0) {
500 LOG_INFO("It looks like the target is running ChibiOS without "
505 /* looks like ChibiOS with memory map enabled.*/
512 static int ChibiOS_create(struct target
*target
)
515 while ((i
< CHIBIOS_NUM_PARAMS
) &&
516 (0 != strcmp(ChibiOS_params_list
[i
].target_name
, target
->type
->name
))) {
519 if (i
>= CHIBIOS_NUM_PARAMS
) {
520 LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
521 "list", target
->type
->name
);
525 target
->rtos
->rtos_specific_params
= (void *) &ChibiOS_params_list
[i
];