1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_standard_stackings.h"
31 #include "target/armv7m.h"
32 #include "target/cortex_m.h"
34 #define FREERTOS_MAX_PRIORITIES 63
36 /* FIXME: none of the _width parameters are actually observed properly!
37 * you WILL need to edit more if you actually attempt to target a 8/16/64
41 struct freertos_params
{
42 const char *target_name
;
43 const unsigned char thread_count_width
;
44 const unsigned char pointer_width
;
45 const unsigned char list_next_offset
;
46 const unsigned char list_width
;
47 const unsigned char list_elem_next_offset
;
48 const unsigned char list_elem_content_offset
;
49 const unsigned char thread_stack_offset
;
50 const unsigned char thread_name_offset
;
51 const struct rtos_register_stacking
*stacking_info_cm3
;
52 const struct rtos_register_stacking
*stacking_info_cm4f
;
53 const struct rtos_register_stacking
*stacking_info_cm4f_fpu
;
56 static const struct freertos_params freertos_params_list
[] = {
58 "cortex_m", /* target_name */
59 4, /* thread_count_width; */
60 4, /* pointer_width; */
61 16, /* list_next_offset; */
63 8, /* list_elem_next_offset; */
64 12, /* list_elem_content_offset */
65 0, /* thread_stack_offset; */
66 52, /* thread_name_offset; */
67 &rtos_standard_cortex_m3_stacking
, /* stacking_info */
68 &rtos_standard_cortex_m4f_stacking
,
69 &rtos_standard_cortex_m4f_fpu_stacking
,
72 "hla_target", /* target_name */
73 4, /* thread_count_width; */
74 4, /* pointer_width; */
75 16, /* list_next_offset; */
77 8, /* list_elem_next_offset; */
78 12, /* list_elem_content_offset */
79 0, /* thread_stack_offset; */
80 52, /* thread_name_offset; */
81 &rtos_standard_cortex_m3_stacking
, /* stacking_info */
82 &rtos_standard_cortex_m4f_stacking
,
83 &rtos_standard_cortex_m4f_fpu_stacking
,
86 "nds32_v3", /* target_name */
87 4, /* thread_count_width; */
88 4, /* pointer_width; */
89 16, /* list_next_offset; */
91 8, /* list_elem_next_offset; */
92 12, /* list_elem_content_offset */
93 0, /* thread_stack_offset; */
94 52, /* thread_name_offset; */
95 &rtos_standard_nds32_n1068_stacking
, /* stacking_info */
96 &rtos_standard_cortex_m4f_stacking
,
97 &rtos_standard_cortex_m4f_fpu_stacking
,
101 static bool freertos_detect_rtos(struct target
*target
);
102 static int freertos_create(struct target
*target
);
103 static int freertos_update_threads(struct rtos
*rtos
);
104 static int freertos_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
105 struct rtos_reg
**reg_list
, int *num_regs
);
106 static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[]);
108 struct rtos_type freertos_rtos
= {
111 .detect_rtos
= freertos_detect_rtos
,
112 .create
= freertos_create
,
113 .update_threads
= freertos_update_threads
,
114 .get_thread_reg_list
= freertos_get_thread_reg_list
,
115 .get_symbol_list_to_lookup
= freertos_get_symbol_list_to_lookup
,
118 enum freertos_symbol_values
{
119 FREERTOS_VAL_PX_CURRENT_TCB
= 0,
120 FREERTOS_VAL_PX_READY_TASKS_LISTS
= 1,
121 FREERTOS_VAL_X_DELAYED_TASK_LIST1
= 2,
122 FREERTOS_VAL_X_DELAYED_TASK_LIST2
= 3,
123 FREERTOS_VAL_PX_DELAYED_TASK_LIST
= 4,
124 FREERTOS_VAL_PX_OVERFLOW_DELAYED_TASK_LIST
= 5,
125 FREERTOS_VAL_X_PENDING_READY_LIST
= 6,
126 FREERTOS_VAL_X_TASKS_WAITING_TERMINATION
= 7,
127 FREERTOS_VAL_X_SUSPENDED_TASK_LIST
= 8,
128 FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS
= 9,
129 FREERTOS_VAL_UX_TOP_USED_PRIORITY
= 10,
137 static const struct symbols freertos_symbol_list
[] = {
138 { "pxCurrentTCB", false },
139 { "pxReadyTasksLists", false },
140 { "xDelayedTaskList1", false },
141 { "xDelayedTaskList2", false },
142 { "pxDelayedTaskList", false },
143 { "pxOverflowDelayedTaskList", false },
144 { "xPendingReadyList", false },
145 { "xTasksWaitingTermination", true }, /* Only if INCLUDE_vTaskDelete */
146 { "xSuspendedTaskList", true }, /* Only if INCLUDE_vTaskSuspend */
147 { "uxCurrentNumberOfTasks", false },
148 { "uxTopUsedPriority", true }, /* Unavailable since v7.5.3 */
153 /* this is not safe for little endian yet */
154 /* may be problems reading if sizes are not 32 bit long integers. */
155 /* test mallocs for failure */
157 static int freertos_update_threads(struct rtos
*rtos
)
160 unsigned int tasks_found
= 0;
161 const struct freertos_params
*param
;
163 if (!rtos
->rtos_specific_params
)
166 param
= (const struct freertos_params
*) rtos
->rtos_specific_params
;
168 if (!rtos
->symbols
) {
169 LOG_ERROR("No symbols for FreeRTOS");
173 if (rtos
->symbols
[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS
].address
== 0) {
174 LOG_ERROR("Don't have the number of threads in FreeRTOS");
178 uint32_t thread_list_size
= 0;
179 retval
= target_read_u32(rtos
->target
,
180 rtos
->symbols
[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS
].address
,
182 LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64
", value %" PRIu32
,
183 rtos
->symbols
[FREERTOS_VAL_UX_CURRENT_NUMBER_OF_TASKS
].address
,
186 if (retval
!= ERROR_OK
) {
187 LOG_ERROR("Could not read FreeRTOS thread count from target");
191 /* wipe out previous thread details if any */
192 rtos_free_threadlist(rtos
);
194 /* read the current thread */
195 uint32_t pointer_casts_are_bad
;
196 retval
= target_read_u32(rtos
->target
,
197 rtos
->symbols
[FREERTOS_VAL_PX_CURRENT_TCB
].address
,
198 &pointer_casts_are_bad
);
199 if (retval
!= ERROR_OK
) {
200 LOG_ERROR("Error reading current thread in FreeRTOS thread list");
203 rtos
->current_thread
= pointer_casts_are_bad
;
204 LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64
", value 0x%" PRIx64
,
205 rtos
->symbols
[FREERTOS_VAL_PX_CURRENT_TCB
].address
,
206 rtos
->current_thread
);
208 if ((thread_list_size
== 0) || (rtos
->current_thread
== 0)) {
209 /* Either : No RTOS threads - there is always at least the current execution though */
210 /* OR : No current thread - all threads suspended - show the current execution
212 char tmp_str
[] = "Current Execution";
215 rtos
->thread_details
= malloc(
216 sizeof(struct thread_detail
) * thread_list_size
);
217 if (!rtos
->thread_details
) {
218 LOG_ERROR("Error allocating memory for %d threads", thread_list_size
);
221 rtos
->thread_details
->threadid
= 1;
222 rtos
->thread_details
->exists
= true;
223 rtos
->thread_details
->extra_info_str
= NULL
;
224 rtos
->thread_details
->thread_name_str
= malloc(sizeof(tmp_str
));
225 strcpy(rtos
->thread_details
->thread_name_str
, tmp_str
);
227 if (thread_list_size
== 1) {
228 rtos
->thread_count
= 1;
232 /* create space for new thread details */
233 rtos
->thread_details
= malloc(
234 sizeof(struct thread_detail
) * thread_list_size
);
235 if (!rtos
->thread_details
) {
236 LOG_ERROR("Error allocating memory for %d threads", thread_list_size
);
241 /* Find out how many lists are needed to be read from pxReadyTasksLists, */
242 if (rtos
->symbols
[FREERTOS_VAL_UX_TOP_USED_PRIORITY
].address
== 0) {
243 LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around");
246 uint32_t top_used_priority
= 0;
247 retval
= target_read_u32(rtos
->target
,
248 rtos
->symbols
[FREERTOS_VAL_UX_TOP_USED_PRIORITY
].address
,
250 if (retval
!= ERROR_OK
)
252 LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64
", value %" PRIu32
,
253 rtos
->symbols
[FREERTOS_VAL_UX_TOP_USED_PRIORITY
].address
,
255 if (top_used_priority
> FREERTOS_MAX_PRIORITIES
) {
256 LOG_ERROR("FreeRTOS top used priority is unreasonably big, not proceeding: %" PRIu32
,
261 /* uxTopUsedPriority was defined as configMAX_PRIORITIES - 1
262 * in old FreeRTOS versions (before V7.5.3)
263 * Use contrib/rtos-helpers/FreeRTOS-openocd.c to get compatible symbol
264 * in newer FreeRTOS versions.
265 * Here we restore the original configMAX_PRIORITIES value */
266 unsigned int config_max_priorities
= top_used_priority
+ 1;
268 symbol_address_t
*list_of_lists
=
269 malloc(sizeof(symbol_address_t
) * (config_max_priorities
+ 5));
270 if (!list_of_lists
) {
271 LOG_ERROR("Error allocating memory for %u priorities", config_max_priorities
);
275 unsigned int num_lists
;
276 for (num_lists
= 0; num_lists
< config_max_priorities
; num_lists
++)
277 list_of_lists
[num_lists
] = rtos
->symbols
[FREERTOS_VAL_PX_READY_TASKS_LISTS
].address
+
278 num_lists
* param
->list_width
;
280 list_of_lists
[num_lists
++] = rtos
->symbols
[FREERTOS_VAL_X_DELAYED_TASK_LIST1
].address
;
281 list_of_lists
[num_lists
++] = rtos
->symbols
[FREERTOS_VAL_X_DELAYED_TASK_LIST2
].address
;
282 list_of_lists
[num_lists
++] = rtos
->symbols
[FREERTOS_VAL_X_PENDING_READY_LIST
].address
;
283 list_of_lists
[num_lists
++] = rtos
->symbols
[FREERTOS_VAL_X_SUSPENDED_TASK_LIST
].address
;
284 list_of_lists
[num_lists
++] = rtos
->symbols
[FREERTOS_VAL_X_TASKS_WAITING_TERMINATION
].address
;
286 for (unsigned int i
= 0; i
< num_lists
; i
++) {
287 if (list_of_lists
[i
] == 0)
290 /* Read the number of threads in this list */
291 uint32_t list_thread_count
= 0;
292 retval
= target_read_u32(rtos
->target
,
295 if (retval
!= ERROR_OK
) {
296 LOG_ERROR("Error reading number of threads in FreeRTOS thread list");
300 LOG_DEBUG("FreeRTOS: Read thread count for list %u at 0x%" PRIx64
", value %" PRIu32
,
301 i
, list_of_lists
[i
], list_thread_count
);
303 if (list_thread_count
== 0)
306 /* Read the location of first list item */
307 uint32_t prev_list_elem_ptr
= -1;
308 uint32_t list_elem_ptr
= 0;
309 retval
= target_read_u32(rtos
->target
,
310 list_of_lists
[i
] + param
->list_next_offset
,
312 if (retval
!= ERROR_OK
) {
313 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
317 LOG_DEBUG("FreeRTOS: Read first item for list %u at 0x%" PRIx64
", value 0x%" PRIx32
,
318 i
, list_of_lists
[i
] + param
->list_next_offset
, list_elem_ptr
);
320 while ((list_thread_count
> 0) && (list_elem_ptr
!= 0) &&
321 (list_elem_ptr
!= prev_list_elem_ptr
) &&
322 (tasks_found
< thread_list_size
)) {
323 /* Get the location of the thread structure. */
324 rtos
->thread_details
[tasks_found
].threadid
= 0;
325 retval
= target_read_u32(rtos
->target
,
326 list_elem_ptr
+ param
->list_elem_content_offset
,
327 &pointer_casts_are_bad
);
328 if (retval
!= ERROR_OK
) {
329 LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
333 rtos
->thread_details
[tasks_found
].threadid
= pointer_casts_are_bad
;
334 LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx32
", value 0x%" PRIx64
,
335 list_elem_ptr
+ param
->list_elem_content_offset
,
336 rtos
->thread_details
[tasks_found
].threadid
);
338 /* get thread name */
340 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
341 char tmp_str
[FREERTOS_THREAD_NAME_STR_SIZE
];
343 /* Read the thread name */
344 retval
= target_read_buffer(rtos
->target
,
345 rtos
->thread_details
[tasks_found
].threadid
+ param
->thread_name_offset
,
346 FREERTOS_THREAD_NAME_STR_SIZE
,
347 (uint8_t *)&tmp_str
);
348 if (retval
!= ERROR_OK
) {
349 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
353 tmp_str
[FREERTOS_THREAD_NAME_STR_SIZE
-1] = '\x00';
354 LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64
", value '%s'",
355 rtos
->thread_details
[tasks_found
].threadid
+ param
->thread_name_offset
,
358 if (tmp_str
[0] == '\x00')
359 strcpy(tmp_str
, "No Name");
361 rtos
->thread_details
[tasks_found
].thread_name_str
=
362 malloc(strlen(tmp_str
)+1);
363 strcpy(rtos
->thread_details
[tasks_found
].thread_name_str
, tmp_str
);
364 rtos
->thread_details
[tasks_found
].exists
= true;
366 if (rtos
->thread_details
[tasks_found
].threadid
== rtos
->current_thread
) {
367 char running_str
[] = "State: Running";
368 rtos
->thread_details
[tasks_found
].extra_info_str
= malloc(
369 sizeof(running_str
));
370 strcpy(rtos
->thread_details
[tasks_found
].extra_info_str
,
373 rtos
->thread_details
[tasks_found
].extra_info_str
= NULL
;
378 prev_list_elem_ptr
= list_elem_ptr
;
380 retval
= target_read_u32(rtos
->target
,
381 prev_list_elem_ptr
+ param
->list_elem_next_offset
,
383 if (retval
!= ERROR_OK
) {
384 LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
388 LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx32
", value 0x%" PRIx32
,
389 prev_list_elem_ptr
+ param
->list_elem_next_offset
,
395 rtos
->thread_count
= tasks_found
;
399 static int freertos_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
400 struct rtos_reg
**reg_list
, int *num_regs
)
403 const struct freertos_params
*param
;
404 int64_t stack_ptr
= 0;
412 if (!rtos
->rtos_specific_params
)
415 param
= (const struct freertos_params
*) rtos
->rtos_specific_params
;
417 /* Read the stack pointer */
418 uint32_t pointer_casts_are_bad
;
419 retval
= target_read_u32(rtos
->target
,
420 thread_id
+ param
->thread_stack_offset
,
421 &pointer_casts_are_bad
);
422 if (retval
!= ERROR_OK
) {
423 LOG_ERROR("Error reading stack frame from FreeRTOS thread");
426 stack_ptr
= pointer_casts_are_bad
;
427 LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64
", value 0x%" PRIx64
,
428 thread_id
+ param
->thread_stack_offset
,
431 /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
432 int cm4_fpu_enabled
= 0;
433 struct armv7m_common
*armv7m_target
= target_to_armv7m(rtos
->target
);
434 if (is_armv7m(armv7m_target
)) {
435 if (armv7m_target
->fp_feature
== FPV4_SP
) {
436 /* Found ARM v7m target which includes a FPU */
439 retval
= target_read_u32(rtos
->target
, FPU_CPACR
, &cpacr
);
440 if (retval
!= ERROR_OK
) {
441 LOG_ERROR("Could not read CPACR register to check FPU state");
445 /* Check if CP10 and CP11 are set to full access. */
446 if (cpacr
& 0x00F00000) {
447 /* Found target with enabled FPU */
453 if (cm4_fpu_enabled
== 1) {
454 /* Read the LR to decide between stacking with or without FPU */
456 retval
= target_read_u32(rtos
->target
,
459 if (retval
!= ERROR_OK
) {
460 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread");
463 if ((lr_svc
& 0x10) == 0)
464 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info_cm4f_fpu
, stack_ptr
, reg_list
, num_regs
);
466 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info_cm4f
, stack_ptr
, reg_list
, num_regs
);
468 return rtos_generic_stack_read(rtos
->target
, param
->stacking_info_cm3
, stack_ptr
, reg_list
, num_regs
);
471 static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
474 *symbol_list
= calloc(
475 ARRAY_SIZE(freertos_symbol_list
), sizeof(struct symbol_table_elem
));
477 for (i
= 0; i
< ARRAY_SIZE(freertos_symbol_list
); i
++) {
478 (*symbol_list
)[i
].symbol_name
= freertos_symbol_list
[i
].name
;
479 (*symbol_list
)[i
].optional
= freertos_symbol_list
[i
].optional
;
487 static int freertos_set_current_thread(struct rtos
*rtos
, threadid_t thread_id
)
492 static int freertos_get_thread_ascii_info(struct rtos
*rtos
, threadid_t thread_id
, char **info
)
495 const struct freertos_params
*param
;
503 if (!rtos
->rtos_specific_params
)
506 param
= (const struct freertos_params
*) rtos
->rtos_specific_params
;
508 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
509 char tmp_str
[FREERTOS_THREAD_NAME_STR_SIZE
];
511 /* Read the thread name */
512 retval
= target_read_buffer(rtos
->target
,
513 thread_id
+ param
->thread_name_offset
,
514 FREERTOS_THREAD_NAME_STR_SIZE
,
515 (uint8_t *)&tmp_str
);
516 if (retval
!= ERROR_OK
) {
517 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
520 tmp_str
[FREERTOS_THREAD_NAME_STR_SIZE
-1] = '\x00';
522 if (tmp_str
[0] == '\x00')
523 strcpy(tmp_str
, "No Name");
525 *info
= malloc(strlen(tmp_str
)+1);
526 strcpy(*info
, tmp_str
);
532 static bool freertos_detect_rtos(struct target
*target
)
534 if ((target
->rtos
->symbols
) &&
535 (target
->rtos
->symbols
[FREERTOS_VAL_PX_READY_TASKS_LISTS
].address
!= 0)) {
536 /* looks like FreeRTOS */
542 static int freertos_create(struct target
*target
)
544 for (unsigned int i
= 0; i
< ARRAY_SIZE(freertos_params_list
); i
++)
545 if (strcmp(freertos_params_list
[i
].target_name
, target
->type
->name
) == 0) {
546 target
->rtos
->rtos_specific_params
= (void *)&freertos_params_list
[i
];
550 LOG_ERROR("Could not find target in FreeRTOS compatibility list");
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)