667875c370c931329eef3c5b08dfbbdc4c0c60f6
[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 static const char * const FreeRTOS_symbol_list[] = {
123 "pxCurrentTCB",
124 "pxReadyTasksLists",
125 "xDelayedTaskList1",
126 "xDelayedTaskList2",
127 "pxDelayedTaskList",
128 "pxOverflowDelayedTaskList",
129 "xPendingReadyList",
130 "xTasksWaitingTermination",
131 "xSuspendedTaskList",
132 "uxCurrentNumberOfTasks",
133 "uxTopUsedPriority",
134 NULL
135 };
136
137 /* TODO: */
138 /* this is not safe for little endian yet */
139 /* may be problems reading if sizes are not 32 bit long integers. */
140 /* test mallocs for failure */
141
142 static int FreeRTOS_update_threads(struct rtos *rtos)
143 {
144 int i = 0;
145 int retval;
146 int tasks_found = 0;
147 const struct FreeRTOS_params *param;
148
149 if (rtos->rtos_specific_params == NULL)
150 return -1;
151
152 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
153
154 if (rtos->symbols == NULL) {
155 LOG_ERROR("No symbols for FreeRTOS");
156 return -3;
157 }
158
159 if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) {
160 LOG_ERROR("Don't have the number of threads in FreeRTOS");
161 return -2;
162 }
163
164 int thread_list_size = 0;
165 retval = target_read_buffer(rtos->target,
166 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
167 param->thread_count_width,
168 (uint8_t *)&thread_list_size);
169 LOG_DEBUG("FreeRTOS: Read uxCurrentNumberOfTasks at 0x%" PRIx64 ", value %d\r\n",
170 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
171 thread_list_size);
172
173 if (retval != ERROR_OK) {
174 LOG_ERROR("Could not read FreeRTOS thread count from target");
175 return retval;
176 }
177
178 /* wipe out previous thread details if any */
179 rtos_free_threadlist(rtos);
180
181 /* read the current thread */
182 retval = target_read_buffer(rtos->target,
183 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
184 param->pointer_width,
185 (uint8_t *)&rtos->current_thread);
186 if (retval != ERROR_OK) {
187 LOG_ERROR("Error reading current thread in FreeRTOS thread list");
188 return retval;
189 }
190 LOG_DEBUG("FreeRTOS: Read pxCurrentTCB at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
191 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
192 rtos->current_thread);
193
194 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
195 /* Either : No RTOS threads - there is always at least the current execution though */
196 /* OR : No current thread - all threads suspended - show the current execution
197 * of idling */
198 char tmp_str[] = "Current Execution";
199 thread_list_size++;
200 tasks_found++;
201 rtos->thread_details = malloc(
202 sizeof(struct thread_detail) * thread_list_size);
203 if (!rtos->thread_details) {
204 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
205 return ERROR_FAIL;
206 }
207 rtos->thread_details->threadid = 1;
208 rtos->thread_details->exists = true;
209 rtos->thread_details->display_str = NULL;
210 rtos->thread_details->extra_info_str = NULL;
211 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
212 strcpy(rtos->thread_details->thread_name_str, tmp_str);
213
214 if (thread_list_size == 1) {
215 rtos->thread_count = 1;
216 return ERROR_OK;
217 }
218 } else {
219 /* create space for new thread details */
220 rtos->thread_details = malloc(
221 sizeof(struct thread_detail) * thread_list_size);
222 if (!rtos->thread_details) {
223 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
224 return ERROR_FAIL;
225 }
226 }
227
228 /* Find out how many lists are needed to be read from pxReadyTasksLists, */
229 int64_t max_used_priority = 0;
230 retval = target_read_buffer(rtos->target,
231 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
232 param->pointer_width,
233 (uint8_t *)&max_used_priority);
234 if (retval != ERROR_OK)
235 return retval;
236 LOG_DEBUG("FreeRTOS: Read uxTopUsedPriority at 0x%" PRIx64 ", value %" PRId64 "\r\n",
237 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
238 max_used_priority);
239 if (max_used_priority > FREERTOS_MAX_PRIORITIES) {
240 LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "",
241 max_used_priority);
242 return ERROR_FAIL;
243 }
244
245 symbol_address_t *list_of_lists =
246 malloc(sizeof(symbol_address_t) *
247 (max_used_priority+1 + 5));
248 if (!list_of_lists) {
249 LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority);
250 return ERROR_FAIL;
251 }
252
253 int num_lists;
254 for (num_lists = 0; num_lists <= max_used_priority; num_lists++)
255 list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
256 num_lists * param->list_width;
257
258 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address;
259 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address;
260 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address;
261 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address;
262 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address;
263
264 for (i = 0; i < num_lists; i++) {
265 if (list_of_lists[i] == 0)
266 continue;
267
268 /* Read the number of threads in this list */
269 int64_t list_thread_count = 0;
270 retval = target_read_buffer(rtos->target,
271 list_of_lists[i],
272 param->thread_count_width,
273 (uint8_t *)&list_thread_count);
274 if (retval != ERROR_OK) {
275 LOG_ERROR("Error reading number of threads in FreeRTOS thread list");
276 free(list_of_lists);
277 return retval;
278 }
279 LOG_DEBUG("FreeRTOS: Read thread count for list %d at 0x%" PRIx64 ", value %" PRId64 "\r\n",
280 i, list_of_lists[i], list_thread_count);
281
282 if (list_thread_count == 0)
283 continue;
284
285 /* Read the location of first list item */
286 uint64_t prev_list_elem_ptr = -1;
287 uint64_t list_elem_ptr = 0;
288 retval = target_read_buffer(rtos->target,
289 list_of_lists[i] + param->list_next_offset,
290 param->pointer_width,
291 (uint8_t *)&list_elem_ptr);
292 if (retval != ERROR_OK) {
293 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
294 free(list_of_lists);
295 return retval;
296 }
297 LOG_DEBUG("FreeRTOS: Read first item for list %d at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
298 i, list_of_lists[i] + param->list_next_offset, list_elem_ptr);
299
300 while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
301 (list_elem_ptr != prev_list_elem_ptr) &&
302 (tasks_found < thread_list_size)) {
303 /* Get the location of the thread structure. */
304 rtos->thread_details[tasks_found].threadid = 0;
305 retval = target_read_buffer(rtos->target,
306 list_elem_ptr + param->list_elem_content_offset,
307 param->pointer_width,
308 (uint8_t *)&(rtos->thread_details[tasks_found].threadid));
309 if (retval != ERROR_OK) {
310 LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
311 free(list_of_lists);
312 return retval;
313 }
314 LOG_DEBUG("FreeRTOS: Read Thread ID at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
315 list_elem_ptr + param->list_elem_content_offset,
316 rtos->thread_details[tasks_found].threadid);
317
318 /* get thread name */
319
320 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
321 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
322
323 /* Read the thread name */
324 retval = target_read_buffer(rtos->target,
325 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
326 FREERTOS_THREAD_NAME_STR_SIZE,
327 (uint8_t *)&tmp_str);
328 if (retval != ERROR_OK) {
329 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
330 free(list_of_lists);
331 return retval;
332 }
333 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
334 LOG_DEBUG("FreeRTOS: Read Thread Name at 0x%" PRIx64 ", value \"%s\"\r\n",
335 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
336 tmp_str);
337
338 if (tmp_str[0] == '\x00')
339 strcpy(tmp_str, "No Name");
340
341 rtos->thread_details[tasks_found].thread_name_str =
342 malloc(strlen(tmp_str)+1);
343 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
344 rtos->thread_details[tasks_found].display_str = NULL;
345 rtos->thread_details[tasks_found].exists = true;
346
347 if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
348 char running_str[] = "Running";
349 rtos->thread_details[tasks_found].extra_info_str = malloc(
350 sizeof(running_str));
351 strcpy(rtos->thread_details[tasks_found].extra_info_str,
352 running_str);
353 } else
354 rtos->thread_details[tasks_found].extra_info_str = NULL;
355
356 tasks_found++;
357 list_thread_count--;
358
359 prev_list_elem_ptr = list_elem_ptr;
360 list_elem_ptr = 0;
361 retval = target_read_buffer(rtos->target,
362 prev_list_elem_ptr + param->list_elem_next_offset,
363 param->pointer_width,
364 (uint8_t *)&list_elem_ptr);
365 if (retval != ERROR_OK) {
366 LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
367 free(list_of_lists);
368 return retval;
369 }
370 LOG_DEBUG("FreeRTOS: Read next thread location at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
371 prev_list_elem_ptr + param->list_elem_next_offset,
372 list_elem_ptr);
373 }
374 }
375
376 free(list_of_lists);
377 rtos->thread_count = tasks_found;
378 return 0;
379 }
380
381 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
382 {
383 int retval;
384 const struct FreeRTOS_params *param;
385 int64_t stack_ptr = 0;
386
387 *hex_reg_list = NULL;
388 if (rtos == NULL)
389 return -1;
390
391 if (thread_id == 0)
392 return -2;
393
394 if (rtos->rtos_specific_params == NULL)
395 return -1;
396
397 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
398
399 /* Read the stack pointer */
400 retval = target_read_buffer(rtos->target,
401 thread_id + param->thread_stack_offset,
402 param->pointer_width,
403 (uint8_t *)&stack_ptr);
404 if (retval != ERROR_OK) {
405 LOG_ERROR("Error reading stack frame from FreeRTOS thread");
406 return retval;
407 }
408 LOG_DEBUG("FreeRTOS: Read stack pointer at 0x%" PRIx64 ", value 0x%" PRIx64 "\r\n",
409 thread_id + param->thread_stack_offset,
410 stack_ptr);
411
412 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
413 }
414
415 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
416 {
417 unsigned int i;
418 *symbol_list = calloc(
419 ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(symbol_table_elem_t));
420
421 for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++)
422 (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i];
423
424 return 0;
425 }
426
427 #if 0
428
429 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id)
430 {
431 return 0;
432 }
433
434 static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info)
435 {
436 int retval;
437 const struct FreeRTOS_params *param;
438
439 if (rtos == NULL)
440 return -1;
441
442 if (thread_id == 0)
443 return -2;
444
445 if (rtos->rtos_specific_params == NULL)
446 return -3;
447
448 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
449
450 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
451 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
452
453 /* Read the thread name */
454 retval = target_read_buffer(rtos->target,
455 thread_id + param->thread_name_offset,
456 FREERTOS_THREAD_NAME_STR_SIZE,
457 (uint8_t *)&tmp_str);
458 if (retval != ERROR_OK) {
459 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
460 return retval;
461 }
462 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
463
464 if (tmp_str[0] == '\x00')
465 strcpy(tmp_str, "No Name");
466
467 *info = malloc(strlen(tmp_str)+1);
468 strcpy(*info, tmp_str);
469 return 0;
470 }
471
472 #endif
473
474 static int FreeRTOS_detect_rtos(struct target *target)
475 {
476 if ((target->rtos->symbols != NULL) &&
477 (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) {
478 /* looks like FreeRTOS */
479 return 1;
480 }
481 return 0;
482 }
483
484 static int FreeRTOS_create(struct target *target)
485 {
486 int i = 0;
487 while ((i < FREERTOS_NUM_PARAMS) &&
488 (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) {
489 i++;
490 }
491 if (i >= FREERTOS_NUM_PARAMS) {
492 LOG_ERROR("Could not find target in FreeRTOS compatibility list");
493 return -1;
494 }
495
496 target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i];
497 return 0;
498 }

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)