acf3689fafe1ea79eacc07f71fc34d1cac6390f6
[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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 const struct FreeRTOS_params FreeRTOS_params_list[] = {
52 {
53 "cortex_m3", /* 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
78 #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params)))
79
80 static int FreeRTOS_detect_rtos(struct target *target);
81 static int FreeRTOS_create(struct target *target);
82 static int FreeRTOS_update_threads(struct rtos *rtos);
83 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
84 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
85
86 struct rtos_type FreeRTOS_rtos = {
87 .name = "FreeRTOS",
88
89 .detect_rtos = FreeRTOS_detect_rtos,
90 .create = FreeRTOS_create,
91 .update_threads = FreeRTOS_update_threads,
92 .get_thread_reg_list = FreeRTOS_get_thread_reg_list,
93 .get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup,
94 };
95
96 enum FreeRTOS_symbol_values {
97 FreeRTOS_VAL_pxCurrentTCB = 0,
98 FreeRTOS_VAL_pxReadyTasksLists = 1,
99 FreeRTOS_VAL_xDelayedTaskList1 = 2,
100 FreeRTOS_VAL_xDelayedTaskList2 = 3,
101 FreeRTOS_VAL_pxDelayedTaskList = 4,
102 FreeRTOS_VAL_pxOverflowDelayedTaskList = 5,
103 FreeRTOS_VAL_xPendingReadyList = 6,
104 FreeRTOS_VAL_xTasksWaitingTermination = 7,
105 FreeRTOS_VAL_xSuspendedTaskList = 8,
106 FreeRTOS_VAL_uxCurrentNumberOfTasks = 9,
107 FreeRTOS_VAL_uxTopUsedPriority = 10,
108 };
109
110 static char *FreeRTOS_symbol_list[] = {
111 "pxCurrentTCB",
112 "pxReadyTasksLists",
113 "xDelayedTaskList1",
114 "xDelayedTaskList2",
115 "pxDelayedTaskList",
116 "pxOverflowDelayedTaskList",
117 "xPendingReadyList",
118 "xTasksWaitingTermination",
119 "xSuspendedTaskList",
120 "uxCurrentNumberOfTasks",
121 "uxTopUsedPriority",
122 NULL
123 };
124
125 /* TODO: */
126 /* this is not safe for little endian yet */
127 /* may be problems reading if sizes are not 32 bit long integers. */
128 /* test mallocs for failure */
129
130 static int FreeRTOS_update_threads(struct rtos *rtos)
131 {
132 int i = 0;
133 int retval;
134 int tasks_found = 0;
135 const struct FreeRTOS_params *param;
136
137 if (rtos->rtos_specific_params == NULL)
138 return -1;
139
140 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
141
142 if (rtos->symbols == NULL) {
143 LOG_ERROR("No symbols for FreeRTOS");
144 return -3;
145 }
146
147 if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) {
148 LOG_ERROR("Don't have the number of threads in FreeRTOS");
149 return -2;
150 }
151
152 int thread_list_size = 0;
153 retval = target_read_buffer(rtos->target,
154 rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address,
155 param->thread_count_width,
156 (uint8_t *)&thread_list_size);
157
158 if (retval != ERROR_OK) {
159 LOG_ERROR("Could not read FreeRTOS thread count from target");
160 return retval;
161 }
162
163 /* wipe out previous thread details if any */
164 if (rtos->thread_details != NULL) {
165 int j;
166 for (j = 0; j < rtos->thread_count; j++) {
167 if (rtos->thread_details[j].display_str != NULL) {
168 free(rtos->thread_details[j].display_str);
169 rtos->thread_details[j].display_str = NULL;
170 }
171 if (rtos->thread_details[j].thread_name_str != NULL) {
172 free(rtos->thread_details[j].thread_name_str);
173 rtos->thread_details[j].thread_name_str = NULL;
174 }
175 if (rtos->thread_details[j].extra_info_str != NULL) {
176 free(rtos->thread_details[j].extra_info_str);
177 rtos->thread_details[j].extra_info_str = NULL;
178 }
179 }
180 free(rtos->thread_details);
181 rtos->thread_details = NULL;
182 }
183
184 /* read the current thread */
185 retval = target_read_buffer(rtos->target,
186 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
187 param->pointer_width,
188 (uint8_t *)&rtos->current_thread);
189 if (retval != ERROR_OK) {
190 LOG_ERROR("Error reading current thread in FreeRTOS thread list");
191 return retval;
192 }
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 = (struct thread_detail *) 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 = (char *) 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 = (struct thread_detail *) 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 if (max_used_priority > FREERTOS_MAX_PRIORITIES) {
237 LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "",
238 max_used_priority);
239 return ERROR_FAIL;
240 }
241
242 symbol_address_t *list_of_lists =
243 (symbol_address_t *)malloc(sizeof(symbol_address_t) *
244 (max_used_priority+1 + 5));
245 if (!list_of_lists) {
246 LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority);
247 return ERROR_FAIL;
248 }
249
250 int num_lists;
251 for (num_lists = 0; num_lists <= max_used_priority; num_lists++)
252 list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address +
253 num_lists * param->list_width;
254
255 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address;
256 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address;
257 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address;
258 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address;
259 list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address;
260
261 for (i = 0; i < num_lists; i++) {
262 if (list_of_lists[i] == 0)
263 continue;
264
265 /* Read the number of threads in this list */
266 int64_t list_thread_count = 0;
267 retval = target_read_buffer(rtos->target,
268 list_of_lists[i],
269 param->thread_count_width,
270 (uint8_t *)&list_thread_count);
271 if (retval != ERROR_OK) {
272 LOG_ERROR("Error reading number of threads in FreeRTOS thread list");
273 free(list_of_lists);
274 return retval;
275 }
276
277 if (list_thread_count == 0)
278 continue;
279
280 /* Read the location of first list item */
281 uint64_t prev_list_elem_ptr = -1;
282 uint64_t list_elem_ptr = 0;
283 retval = target_read_buffer(rtos->target,
284 list_of_lists[i] + param->list_next_offset,
285 param->pointer_width,
286 (uint8_t *)&list_elem_ptr);
287 if (retval != ERROR_OK) {
288 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
289 free(list_of_lists);
290 return retval;
291 }
292
293 while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
294 (list_elem_ptr != prev_list_elem_ptr) &&
295 (tasks_found < thread_list_size)) {
296 /* Get the location of the thread structure. */
297 rtos->thread_details[tasks_found].threadid = 0;
298 retval = target_read_buffer(rtos->target,
299 list_elem_ptr + param->list_elem_content_offset,
300 param->pointer_width,
301 (uint8_t *)&(rtos->thread_details[tasks_found].threadid));
302 if (retval != ERROR_OK) {
303 LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
304 free(list_of_lists);
305 return retval;
306 }
307
308 /* get thread name */
309
310 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
311 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
312
313 /* Read the thread name */
314 retval = target_read_buffer(rtos->target,
315 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
316 FREERTOS_THREAD_NAME_STR_SIZE,
317 (uint8_t *)&tmp_str);
318 if (retval != ERROR_OK) {
319 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
320 free(list_of_lists);
321 return retval;
322 }
323 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
324
325 if (tmp_str[0] == '\x00')
326 strcpy(tmp_str, "No Name");
327
328 rtos->thread_details[tasks_found].thread_name_str =
329 (char *)malloc(strlen(tmp_str)+1);
330 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
331 rtos->thread_details[tasks_found].display_str = NULL;
332 rtos->thread_details[tasks_found].exists = true;
333
334 if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
335 char running_str[] = "Running";
336 rtos->thread_details[tasks_found].extra_info_str = (char *) malloc(
337 sizeof(running_str));
338 strcpy(rtos->thread_details[tasks_found].extra_info_str,
339 running_str);
340 } else
341 rtos->thread_details[tasks_found].extra_info_str = NULL;
342
343 tasks_found++;
344 list_thread_count--;
345
346 prev_list_elem_ptr = list_elem_ptr;
347 list_elem_ptr = 0;
348 retval = target_read_buffer(rtos->target,
349 prev_list_elem_ptr + param->list_elem_next_offset,
350 param->pointer_width,
351 (uint8_t *)&list_elem_ptr);
352 if (retval != ERROR_OK) {
353 LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
354 free(list_of_lists);
355 return retval;
356 }
357 }
358 }
359
360 free(list_of_lists);
361 rtos->thread_count = tasks_found;
362 return 0;
363 }
364
365 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
366 {
367 int retval;
368 const struct FreeRTOS_params *param;
369 int64_t stack_ptr = 0;
370
371 *hex_reg_list = NULL;
372 if (rtos == NULL)
373 return -1;
374
375 if (thread_id == 0)
376 return -2;
377
378 if (rtos->rtos_specific_params == NULL)
379 return -1;
380
381 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
382
383 /* Read the stack pointer */
384 retval = target_read_buffer(rtos->target,
385 thread_id + param->thread_stack_offset,
386 param->pointer_width,
387 (uint8_t *)&stack_ptr);
388 if (retval != ERROR_OK) {
389 LOG_ERROR("Error reading stack frame from FreeRTOS thread");
390 return retval;
391 }
392
393 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
394 }
395
396 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
397 {
398 unsigned int i;
399 *symbol_list = (symbol_table_elem_t *) malloc(
400 sizeof(symbol_table_elem_t) * ARRAY_SIZE(FreeRTOS_symbol_list));
401
402 for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++)
403 (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i];
404
405 return 0;
406 }
407
408 #if 0
409
410 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id)
411 {
412 return 0;
413 }
414
415 static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info)
416 {
417 int retval;
418 const struct FreeRTOS_params *param;
419
420 if (rtos == NULL)
421 return -1;
422
423 if (thread_id == 0)
424 return -2;
425
426 if (rtos->rtos_specific_params == NULL)
427 return -3;
428
429 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
430
431 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
432 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
433
434 /* Read the thread name */
435 retval = target_read_buffer(rtos->target,
436 thread_id + param->thread_name_offset,
437 FREERTOS_THREAD_NAME_STR_SIZE,
438 (uint8_t *)&tmp_str);
439 if (retval != ERROR_OK) {
440 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
441 return retval;
442 }
443 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
444
445 if (tmp_str[0] == '\x00')
446 strcpy(tmp_str, "No Name");
447
448 *info = (char *)malloc(strlen(tmp_str)+1);
449 strcpy(*info, tmp_str);
450 return 0;
451 }
452
453 #endif
454
455 static int FreeRTOS_detect_rtos(struct target *target)
456 {
457 if ((target->rtos->symbols != NULL) &&
458 (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) {
459 /* looks like FreeRTOS */
460 return 1;
461 }
462 return 0;
463 }
464
465 static int FreeRTOS_create(struct target *target)
466 {
467 int i = 0;
468 while ((i < FREERTOS_NUM_PARAMS) &&
469 (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) {
470 i++;
471 }
472 if (i >= FREERTOS_NUM_PARAMS) {
473 LOG_ERROR("Could not find target in FreeRTOS compatibility list");
474 return -1;
475 }
476
477 target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i];
478 return 0;
479 }

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)