openocd: fix SPDX tag format for files .c
[fw/openocd] / src / rtos / chibios.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2012 by Matthias Blaicher                               *
5  *   Matthias Blaicher - matthias@blaicher.com                             *
6  *                                                                         *
7  *   Copyright (C) 2011 by Broadcom Corporation                            *
8  *   Evan Hunter - ehunter@broadcom.com                                    *
9  ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
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"
21 #include "rtos.h"
22 #include "helper/log.h"
23 #include "helper/types.h"
24 #include "rtos_chibios_stackings.h"
25
26 /**
27  * @brief   ChibiOS/RT memory signature record.
28  *
29  * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
30  */
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
45                                                                                                 field.                        */
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
50                                                                                                 field.                        */
51         uint8_t   cf_off_time;            /**< @brief Offset of @p p_time field.  */
52 };
53
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)
57
58 /**
59  * @brief ChibiOS thread states.
60  */
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"
64 };
65
66 #define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states)
67
68 /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
69  * chars ought to be enough.
70  */
71 #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
72
73 struct chibios_params {
74         const char *target_name;
75
76         struct chibios_chdebug *signature;
77         const struct rtos_register_stacking *stacking_info;
78 };
79
80 static struct chibios_params chibios_params_list[] = {
81         {
82         "cortex_m",                                                     /* target_name */
83         0,
84         NULL,                                                                   /* stacking_info */
85         },
86         {
87         "hla_target",                                                   /* target_name */
88         0,
89         NULL,                                                                   /* stacking_info */
90         }
91 };
92
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[]);
99
100 struct rtos_type chibios_rtos = {
101         .name = "chibios",
102
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,
108 };
109
110
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.
114  */
115
116 enum chibios_symbol_values {
117         CHIBIOS_VAL_RLIST = 0,
118         CHIBIOS_VAL_CH = 1,
119         CHIBIOS_VAL_CH_DEBUG = 2
120 };
121
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 */
126         { NULL, 0, false}
127 };
128
129 /* Offset of the rlist structure within the system data structure (ch) */
130 #define CH_RLIST_OFFSET 0x00
131
132 static int chibios_update_memory_signature(struct rtos *rtos)
133 {
134         int retval;
135         struct chibios_params *param;
136         struct chibios_chdebug *signature;
137
138         param = (struct chibios_params *) rtos->rtos_specific_params;
139
140         /* Free existing memory description.*/
141         free(param->signature);
142         param->signature = NULL;
143
144         signature = malloc(sizeof(*signature));
145         if (!signature) {
146                 LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
147                 return -1;
148         }
149
150         retval = target_read_buffer(rtos->target,
151                                                                 rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address,
152                                                                 sizeof(*signature),
153                                                                 (uint8_t *) signature);
154         if (retval != ERROR_OK) {
155                 LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
156                 goto errfree;
157         }
158
159         if (strncmp(signature->ch_identifier, "main", 4) != 0) {
160                 LOG_ERROR("Memory signature identifier does not contain magic bytes.");
161                 goto errfree;
162         }
163
164         if (signature->ch_size < sizeof(*signature)) {
165                 LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
166                                 "than expected");
167                 goto errfree;
168         }
169
170         if (signature->ch_size > sizeof(*signature)) {
171                 LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
172                                         " expected. Assuming compatibility...");
173         }
174
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);
180
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));
185
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!");
191                 free(signature);
192                 return -1;
193         }
194
195         param->signature = signature;
196         return 0;
197
198 errfree:
199         /* Error reading the ChibiOS memory structure */
200         free(signature);
201         param->signature = 0;
202         return -1;
203 }
204
205
206 static int chibios_update_stacking(struct rtos *rtos)
207 {
208         /* Sometimes the stacking can not be determined only by looking at the
209          * target name but only a runtime.
210          *
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.
213          *
214          * Terminating which stacking is used is target depending.
215          *
216          * Assumptions:
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.
224          */
225         int retval;
226
227         if (!rtos->rtos_specific_params)
228                 return -1;
229
230         struct chibios_params *param;
231         param = (struct chibios_params *) rtos->rtos_specific_params;
232
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 */
238                         uint32_t cpacr;
239
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");
243                                 return -1;
244                         }
245
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;
251                                 return 0;
252                         }
253                 }
254
255                 /* Found ARM v7m target with no or disabled FPU */
256                 param->stacking_info = &rtos_chibios_arm_v7m_stacking;
257                 return 0;
258         }
259
260         return -1;
261 }
262
263 static int chibios_update_threads(struct rtos *rtos)
264 {
265         int retval;
266         const struct chibios_params *param;
267         int tasks_found = 0;
268         int rtos_valid = -1;
269
270         if (!rtos->rtos_specific_params)
271                 return -1;
272
273         if (!rtos->symbols) {
274                 LOG_ERROR("No symbols for ChibiOS");
275                 return -3;
276         }
277
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");
284                         return retval;
285                 }
286         }
287
288         /* wipe out previous thread details if any */
289         rtos_free_threadlist(rtos);
290
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
293          * threads. */
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;
298         uint32_t current;
299         uint32_t previous;
300         uint32_t older;
301
302         current = rlist;
303         previous = rlist;
304         while (1) {
305                 retval = target_read_u32(rtos->target,
306                                                                  current + signature->cf_off_newer, &current);
307                 if (retval != ERROR_OK) {
308                         LOG_ERROR("Could not read next ChibiOS thread");
309                         return retval;
310                 }
311                 /* Could be NULL if the kernel is not initialized yet or if the
312                  * registry is corrupted. */
313                 if (current == 0) {
314                         LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
315
316                         rtos_valid = 0;
317                         break;
318                 }
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");
325                         rtos_valid = 0;
326                         break;
327                 }
328                 /* Check for full iteration of the linked list. */
329                 if (current == rlist)
330                         break;
331                 tasks_found++;
332                 previous = current;
333         }
334         if (!rtos_valid) {
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.");
338
339                 const char tmp_thread_name[] = "Current Execution";
340                 const char tmp_thread_extra_info[] = "No RTOS thread";
341
342                 rtos->thread_details = malloc(
343                                 sizeof(struct thread_detail));
344                 rtos->thread_details->threadid = 1;
345                 rtos->thread_details->exists = true;
346
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);
350
351                 rtos->thread_details->thread_name_str = malloc(
352                                 sizeof(tmp_thread_name));
353                 strcpy(rtos->thread_details->thread_name_str, tmp_thread_name);
354
355                 rtos->current_thread = 1;
356                 rtos->thread_count = 1;
357                 return ERROR_OK;
358         }
359
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");
365                 return -1;
366         }
367
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];
374
375                 retval = target_read_u32(rtos->target,
376                                                                  current + signature->cf_off_newer, &current);
377                 if (retval != ERROR_OK) {
378                         LOG_ERROR("Could not read next ChibiOS thread");
379                         return -6;
380                 }
381
382                 /* Check for full iteration of the linked list. */
383                 if (current == rlist)
384                         break;
385
386                 /* Save the thread pointer */
387                 curr_thrd_details->threadid = current;
388
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");
394                         return retval;
395                 }
396
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");
403                         return retval;
404                 }
405                 tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE - 1] = '\x00';
406
407                 if (tmp_str[0] == '\x00')
408                         strcpy(tmp_str, "No Name");
409
410                 curr_thrd_details->thread_name_str = malloc(
411                                 strlen(tmp_str) + 1);
412                 strcpy(curr_thrd_details->thread_name_str, tmp_str);
413
414                 /* State info */
415                 uint8_t thread_state;
416                 const char *state_desc;
417
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");
422                         return retval;
423                 }
424
425
426                 if (thread_state < CHIBIOS_NUM_STATES)
427                         state_desc = chibios_thread_states[thread_state];
428                 else
429                         state_desc = "Unknown";
430
431                 curr_thrd_details->extra_info_str = malloc(strlen(
432                                         state_desc)+8);
433                 sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc);
434
435                 curr_thrd_details->exists = true;
436
437                 curr_thrd_details++;
438         }
439
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,
444                                                          &current_thrd);
445         if (retval != ERROR_OK) {
446                 LOG_ERROR("Could not read current Thread from ChibiOS target");
447                 return retval;
448         }
449         rtos->current_thread = current_thrd;
450
451         return 0;
452 }
453
454 static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
455                 struct rtos_reg **reg_list, int *num_regs)
456 {
457         int retval;
458         const struct chibios_params *param;
459         uint32_t stack_ptr = 0;
460
461         if ((!rtos) || (thread_id == 0) ||
462                         (!rtos->rtos_specific_params))
463                 return -1;
464
465         param = (const struct chibios_params *) rtos->rtos_specific_params;
466
467         if (!param->signature)
468                 return -1;
469
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);
474                 return -1;
475         }
476
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");
482                 return retval;
483         }
484
485         return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
486 }
487
488 static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
489 {
490         *symbol_list = malloc(sizeof(chibios_symbol_list));
491
492         if (!*symbol_list)
493                 return ERROR_FAIL;
494
495         memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list));
496         return 0;
497 }
498
499 static bool chibios_detect_rtos(struct target *target)
500 {
501         if ((target->rtos->symbols) &&
502                         ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) ||
503                          (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) {
504
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.");
508                         return false;
509                 }
510
511                 /* looks like ChibiOS with memory map enabled.*/
512                 return true;
513         }
514
515         return false;
516 }
517
518 static int chibios_create(struct target *target)
519 {
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];
523                         return 0;
524                 }
525
526         LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
527                                 "list", target->type->name);
528         return -1;
529 }