rtos: add instructions and helper code to make FreeRTOS work again
[openocd.git] / src / rtos / FreeRTOS.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
4 * *
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. *
9 * *
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. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_standard_stackings.h"
33
34 #define FREERTOS_MAX_PRIORITIES 63
35
36 #define FreeRTOS_STRUCT(int_type, ptr_type, list_prev_offset)
37
38 struct FreeRTOS_params {
39 const char *target_name;
40 const unsigned char thread_count_width;
41 const unsigned char pointer_width;
42 const unsigned char list_next_offset;
43 const unsigned char list_width;
44 const unsigned char list_elem_next_offset;
45 const unsigned char list_elem_content_offset;
46 const unsigned char thread_stack_offset;
47 const unsigned char thread_name_offset;
48 const struct rtos_register_stacking *stacking_info;
49 };
50
51 static const struct FreeRTOS_params FreeRTOS_params_list[] = {
52 {
53 "cortex_m", /* target_name */
54 4, /* thread_count_width; */
55 4, /* pointer_width; */
56 16, /* list_next_offset; */
57 20, /* list_width; */
58 8, /* list_elem_next_offset; */
59 12, /* list_elem_content_offset */
60 0, /* thread_stack_offset; */
61 52, /* thread_name_offset; */
62 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
63 },
64 {
65 "hla_target", /* target_name */
66 4, /* thread_count_width; */
67 4, /* pointer_width; */
68 16, /* list_next_offset; */
69 20, /* list_width; */
70 8, /* list_elem_next_offset; */
71 12, /* list_elem_content_offset */
72 0, /* thread_stack_offset; */
73 52, /* thread_name_offset; */
74 &rtos_standard_Cortex_M3_stacking, /* stacking_info */
75 },
76 {
77 "nds32_v3", /* target_name */
78 4, /* thread_count_width; */
79 4, /* pointer_width; */
80 16, /* list_next_offset; */
81 20, /* list_width; */
82 8, /* list_elem_next_offset; */
83 12, /* list_elem_content_offset */
84 0, /* thread_stack_offset; */
85 52, /* thread_name_offset; */
86 &rtos_standard_NDS32_N1068_stacking, /* stacking_info */
87 },
88 };
89
90 #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params)))
91
92 static int FreeRTOS_detect_rtos(struct target *target);
93 static int FreeRTOS_create(struct target *target);
94 static int FreeRTOS_update_threads(struct rtos *rtos);
95 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
96 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
97
98 struct rtos_type FreeRTOS_rtos = {
99 .name = "FreeRTOS",
100
101 .detect_rtos = FreeRTOS_detect_rtos,
102 .create = FreeRTOS_create,
103 .update_threads = FreeRTOS_update_threads,
104 .get_thread_reg_list = FreeRTOS_get_thread_reg_list,
105 .get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup,
106 };
107
108 enum FreeRTOS_symbol_values {
109 FreeRTOS_VAL_pxCurrentTCB = 0,
110 FreeRTOS_VAL_pxReadyTasksLists = 1,
111 FreeRTOS_VAL_xDelayedTaskList1 = 2,
112 FreeRTOS_VAL_xDelayedTaskList2 = 3,
113 FreeRTOS_VAL_pxDelayedTaskList = 4,
114 FreeRTOS_VAL_pxOverflowDelayedTaskList = 5,
115 FreeRTOS_VAL_xPendingReadyList = 6,
116 FreeRTOS_VAL_xTasksWaitingTermination = 7,
117 FreeRTOS_VAL_xSuspendedTaskList = 8,
118 FreeRTOS_VAL_uxCurrentNumberOfTasks = 9,
119 FreeRTOS_VAL_uxTopUsedPriority = 10,
120 };
121
122 struct symbols {
123 const char *name;
124 bool optional;
125 };
126
127 static const struct symbols FreeRTOS_symbol_list[] = {
128 { "pxCurrentTCB", false },
129 { "pxReadyTasksLists", false },
130 { "xDelayedTaskList1", false },
131 { "xDelayedTaskList2", false },
132 { "pxDelayedTaskList", false },
133 { "pxOverflowDelayedTaskList", false },
134 { "xPendingReadyList", false },
135 { "xTasksWaitingTermination", true }, /* Only if INCLUDE_vTaskDelete */
136 { "xSuspendedTaskList", true }, /* Only if INCLUDE_vTaskSuspend */
137 { "uxCurrentNumberOfTasks", false },
138 { "uxTopUsedPriority", true }, /* Unavailable since v7.5.3 */
139 { NULL, false }
140 };
141
142 /* TODO: */
143 /* this is not safe for little endian yet */
144 /* may be problems reading if sizes are not 32 bit long integers. */
145 /* test mallocs for failure */
146
147 static int FreeRTOS_update_threads(struct rtos *rtos)
148 {
149 int i = 0;
150 int retval;
151 int tasks_found = 0;
152 const struct FreeRTOS_params *param;
153
154 if (rtos->rtos_specific_params == NULL)
155 return -1;
156
157 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
158
159 if (rtos->symbols == NULL) {
160 LOG_ERROR("No symbols for FreeRTOS");
161 return -3;
162 }
163
164 if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) {
165 LOG_ERROR("Don't have the number of threads in FreeRTOS");
166 return -2;
167 }
168
169 int thread_list_size = 0;
170 retval = target_read_buffer(rtos->target,
171 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
172 param->thread_count_width,
173 (uint8_t *)&thread_list_size);
174 LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %d\r\n",
175 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
176 thread_list_size);
177
178 if (retval != ERROR_OK) {
179 LOG_ERROR("Could not read FreeRTOS thread count from target");
180 return retval;
181 }
182
183 /* wipe out previous thread details if any */
184 rtos_free_threadlist(rtos);
185
186 /* read the current thread */
187 retval = target_read_buffer(rtos->target,
188 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
189 param->pointer_width,
190 (uint8_t *)&rtos->current_thread);
191 if (retval != ERROR_OK) {
192 LOG_ERROR("Error reading current thread in FreeRTOS thread list");
193 return retval;
194 }
195 LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
196 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
197 rtos->current_thread);
198
199 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
200 /* Either : No RTOS threads - there is always at least the current execution though */
201 /* OR : No current thread - all threads suspended - show the current execution
202 * of idling */
203 char tmp_str[] = "Current Execution";
204 thread_list_size++;
205 tasks_found++;
206 rtos->thread_details = malloc(
207 sizeof(struct thread_detail) * thread_list_size);
208 if (!rtos->thread_details) {
209 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
210 return ERROR_FAIL;
211 }
212 rtos->thread_details->threadid = 1;
213 rtos->thread_details->exists = true;
214 rtos->thread_details->display_str = NULL;
215 rtos->thread_details->extra_info_str = NULL;
216 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
217 strcpy(rtos->thread_details->thread_name_str, tmp_str);
218
219 if (thread_list_size == 1) {
220 rtos->thread_count = 1;
221 return ERROR_OK;
222 }
223 } else {
224 /* create space for new thread details */
225 rtos->thread_details = malloc(
226 sizeof(struct thread_detail) * thread_list_size);
227 if (!rtos->thread_details) {
228 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
229 return ERROR_FAIL;
230 }
231 }
232
233 /* Find out how many lists are needed to be read from pxReadyTasksLists, */
234 if (rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address == 0) {
235 LOG_ERROR("FreeRTOS: uxTopUsedPriority is not defined, consult the OpenOCD manual for a work-around");
236 return ERROR_FAIL;
237 }
238 int64_t max_used_priority = 0;
239 retval = target_read_buffer(rtos->target,
240 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
241 param->pointer_width,
242 (uint8_t *)&max_used_priority);
243 if (retval != ERROR_OK)
244 return retval;
245 LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRId64 "\r\n",
246 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
247 max_used_priority);
248 if (max_used_priority > FREERTOS_MAX_PRIORITIES) {
249 LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "",
250 max_used_priority);
251 return ERROR_FAIL;
252 }
253
254 symbol_address_t *list_of_lists =
255 malloc(sizeof(symbol_address_t) *
256 (max_used_priority+1 + 5));
257 if (!list_of_lists) {
258 LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority);
259 return ERROR_FAIL;
260 }
261
262 int num_lists;
263 for (num_lists = 0; num_lists <= max_used_priority; num_lists++)
264 list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
265 num_lists * param->list_width;
266
267 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address;
268 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address;
269 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address;
270 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address;
271 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address;
272
273 for (i = 0; i < num_lists; i++) {
274 if (list_of_lists[i] == 0)
275 continue;
276
277 /* Read the number of threads in this list */
278 int64_t list_thread_count = 0;
279 retval = target_read_buffer(rtos->target,
280 list_of_lists[i],
281 param->thread_count_width,
282 (uint8_t *)&list_thread_count);
283 if (retval != ERROR_OK) {
284 LOG_ERROR("Error reading number of threads in FreeRTOS thread list");
285 free(list_of_lists);
286 return retval;
287 }
288 LOG_DEBUG("FreeRTOS: Read thread count for list %d at 0x%" PRIx64 ", value %" PRId64 "\r\n",
289 i, list_of_lists[i], list_thread_count);
290
291 if (list_thread_count == 0)
292 continue;
293
294 /* Read the location of first list item */
295 uint64_t prev_list_elem_ptr = -1;
296 uint64_t list_elem_ptr = 0;
297 retval = target_read_buffer(rtos->target,
298 list_of_lists[i] + param->list_next_offset,
299 param->pointer_width,
300 (uint8_t *)&list_elem_ptr);
301 if (retval != ERROR_OK) {
302 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
303 free(list_of_lists);
304 return retval;
305 }
306 LOG_DEBUG("FreeRTOS: Read first item for list %d at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
307 i, list_of_lists[i] + param->list_next_offset, list_elem_ptr);
308
309 while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
310 (list_elem_ptr != prev_list_elem_ptr) &&
311 (tasks_found < thread_list_size)) {
312 /* Get the location of the thread structure. */
313 rtos->thread_details[tasks_found].threadid = 0;
314 retval = target_read_buffer(rtos->target,
315 list_elem_ptr + param->list_elem_content_offset,
316 param->pointer_width,
317 (uint8_t *)&(rtos->thread_details[tasks_found].threadid));
318 if (retval != ERROR_OK) {
319 LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
320 free(list_of_lists);
321 return retval;
322 }
323 LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
324 list_elem_ptr + param->list_elem_content_offset,
325 rtos->thread_details[tasks_found].threadid);
326
327 /* get thread name */
328
329 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
330 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
331
332 /* Read the thread name */
333 retval = target_read_buffer(rtos->target,
334 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
335 FREERTOS_THREAD_NAME_STR_SIZE,
336 (uint8_t *)&tmp_str);
337 if (retval != ERROR_OK) {
338 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
339 free(list_of_lists);
340 return retval;
341 }
342 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
343 LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value \"%s\"\r\n",
344 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
345 tmp_str);
346
347 if (tmp_str[0] == '\x00')
348 strcpy(tmp_str, "No Name");
349
350 rtos->thread_details[tasks_found].thread_name_str =
351 malloc(strlen(tmp_str)+1);
352 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
353 rtos->thread_details[tasks_found].display_str = NULL;
354 rtos->thread_details[tasks_found].exists = true;
355
356 if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
357 char running_str[] = "Running";
358 rtos->thread_details[tasks_found].extra_info_str = malloc(
359 sizeof(running_str));
360 strcpy(rtos->thread_details[tasks_found].extra_info_str,
361 running_str);
362 } else
363 rtos->thread_details[tasks_found].extra_info_str = NULL;
364
365 tasks_found++;
366 list_thread_count--;
367
368 prev_list_elem_ptr = list_elem_ptr;
369 list_elem_ptr = 0;
370 retval = target_read_buffer(rtos->target,
371 prev_list_elem_ptr + param->list_elem_next_offset,
372 param->pointer_width,
373 (uint8_t *)&list_elem_ptr);
374 if (retval != ERROR_OK) {
375 LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
376 free(list_of_lists);
377 return retval;
378 }
379 LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
380 prev_list_elem_ptr + param->list_elem_next_offset,
381 list_elem_ptr);
382 }
383 }
384
385 free(list_of_lists);
386 rtos->thread_count = tasks_found;
387 return 0;
388 }
389
390 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
391 {
392 int retval;
393 const struct FreeRTOS_params *param;
394 int64_t stack_ptr = 0;
395
396 *hex_reg_list = NULL;
397 if (rtos == NULL)
398 return -1;
399
400 if (thread_id == 0)
401 return -2;
402
403 if (rtos->rtos_specific_params == NULL)
404 return -1;
405
406 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
407
408 /* Read the stack pointer */
409 retval = target_read_buffer(rtos->target,
410 thread_id + param->thread_stack_offset,
411 param->pointer_width,
412 (uint8_t *)&stack_ptr);
413 if (retval != ERROR_OK) {
414 LOG_ERROR("Error reading stack frame from FreeRTOS thread");
415 return retval;
416 }
417 LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
418 thread_id + param->thread_stack_offset,
419 stack_ptr);
420
421 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
422 }
423
424 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
425 {
426 unsigned int i;
427 *symbol_list = calloc(
428 ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(symbol_table_elem_t));
429
430 for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++) {
431 (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i].name;
432 (*symbol_list)[i].optional = FreeRTOS_symbol_list[i].optional;
433 }
434
435 return 0;
436 }
437
438 #if 0
439
440 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id)
441 {
442 return 0;
443 }
444
445 static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info)
446 {
447 int retval;
448 const struct FreeRTOS_params *param;
449
450 if (rtos == NULL)
451 return -1;
452
453 if (thread_id == 0)
454 return -2;
455
456 if (rtos->rtos_specific_params == NULL)
457 return -3;
458
459 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
460
461 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
462 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
463
464 /* Read the thread name */
465 retval = target_read_buffer(rtos->target,
466 thread_id + param->thread_name_offset,
467 FREERTOS_THREAD_NAME_STR_SIZE,
468 (uint8_t *)&tmp_str);
469 if (retval != ERROR_OK) {
470 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
471 return retval;
472 }
473 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
474
475 if (tmp_str[0] == '\x00')
476 strcpy(tmp_str, "No Name");
477
478 *info = malloc(strlen(tmp_str)+1);
479 strcpy(*info, tmp_str);
480 return 0;
481 }
482
483 #endif
484
485 static int FreeRTOS_detect_rtos(struct target *target)
486 {
487 if ((target->rtos->symbols != NULL) &&
488 (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) {
489 /* looks like FreeRTOS */
490 return 1;
491 }
492 return 0;
493 }
494
495 static int FreeRTOS_create(struct target *target)
496 {
497 int i = 0;
498 while ((i < FREERTOS_NUM_PARAMS) &&
499 (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) {
500 i++;
501 }
502 if (i >= FREERTOS_NUM_PARAMS) {
503 LOG_ERROR("Could not find target in FreeRTOS compatibility list");
504 return -1;
505 }
506
507 target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i];
508 return 0;
509 }

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)