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