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