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