nds32: support FreeRTOS
[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 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 char *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
170 if (retval != ERROR_OK) {
171 LOG_ERROR("Could not read FreeRTOS thread count from target");
172 return retval;
173 }
174
175 /* wipe out previous thread details if any */
176 if (rtos->thread_details != NULL) {
177 int j;
178 for (j = 0; j < rtos->thread_count; j++) {
179 if (rtos->thread_details[j].display_str != NULL) {
180 free(rtos->thread_details[j].display_str);
181 rtos->thread_details[j].display_str = NULL;
182 }
183 if (rtos->thread_details[j].thread_name_str != NULL) {
184 free(rtos->thread_details[j].thread_name_str);
185 rtos->thread_details[j].thread_name_str = NULL;
186 }
187 if (rtos->thread_details[j].extra_info_str != NULL) {
188 free(rtos->thread_details[j].extra_info_str);
189 rtos->thread_details[j].extra_info_str = NULL;
190 }
191 }
192 free(rtos->thread_details);
193 rtos->thread_details = NULL;
194 }
195
196 /* read the current thread */
197 retval = target_read_buffer(rtos->target,
198 rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address,
199 param->pointer_width,
200 (uint8_t *)&rtos->current_thread);
201 if (retval != ERROR_OK) {
202 LOG_ERROR("Error reading current thread in FreeRTOS thread list");
203 return retval;
204 }
205
206 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
207 /* Either : No RTOS threads - there is always at least the current execution though */
208 /* OR : No current thread - all threads suspended - show the current execution
209 * of idling */
210 char tmp_str[] = "Current Execution";
211 thread_list_size++;
212 tasks_found++;
213 rtos->thread_details = (struct thread_detail *) malloc(
214 sizeof(struct thread_detail) * thread_list_size);
215 if (!rtos->thread_details) {
216 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
217 return ERROR_FAIL;
218 }
219 rtos->thread_details->threadid = 1;
220 rtos->thread_details->exists = true;
221 rtos->thread_details->display_str = NULL;
222 rtos->thread_details->extra_info_str = NULL;
223 rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str));
224 strcpy(rtos->thread_details->thread_name_str, tmp_str);
225
226 if (thread_list_size == 1) {
227 rtos->thread_count = 1;
228 return ERROR_OK;
229 }
230 } else {
231 /* create space for new thread details */
232 rtos->thread_details = (struct thread_detail *) malloc(
233 sizeof(struct thread_detail) * thread_list_size);
234 if (!rtos->thread_details) {
235 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
236 return ERROR_FAIL;
237 }
238 }
239
240 /* Find out how many lists are needed to be read from pxReadyTasksLists, */
241 int64_t max_used_priority = 0;
242 retval = target_read_buffer(rtos->target,
243 rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address,
244 param->pointer_width,
245 (uint8_t *)&max_used_priority);
246 if (retval != ERROR_OK)
247 return retval;
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 (symbol_address_t *)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
289 if (list_thread_count == 0)
290 continue;
291
292 /* Read the location of first list item */
293 uint64_t prev_list_elem_ptr = -1;
294 uint64_t list_elem_ptr = 0;
295 retval = target_read_buffer(rtos->target,
296 list_of_lists[i] + param->list_next_offset,
297 param->pointer_width,
298 (uint8_t *)&list_elem_ptr);
299 if (retval != ERROR_OK) {
300 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
301 free(list_of_lists);
302 return retval;
303 }
304
305 while ((list_thread_count > 0) && (list_elem_ptr != 0) &&
306 (list_elem_ptr != prev_list_elem_ptr) &&
307 (tasks_found < thread_list_size)) {
308 /* Get the location of the thread structure. */
309 rtos->thread_details[tasks_found].threadid = 0;
310 retval = target_read_buffer(rtos->target,
311 list_elem_ptr + param->list_elem_content_offset,
312 param->pointer_width,
313 (uint8_t *)&(rtos->thread_details[tasks_found].threadid));
314 if (retval != ERROR_OK) {
315 LOG_ERROR("Error reading thread list item object in FreeRTOS thread list");
316 free(list_of_lists);
317 return retval;
318 }
319
320 /* get thread name */
321
322 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
323 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
324
325 /* Read the thread name */
326 retval = target_read_buffer(rtos->target,
327 rtos->thread_details[tasks_found].threadid + param->thread_name_offset,
328 FREERTOS_THREAD_NAME_STR_SIZE,
329 (uint8_t *)&tmp_str);
330 if (retval != ERROR_OK) {
331 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
332 free(list_of_lists);
333 return retval;
334 }
335 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
336
337 if (tmp_str[0] == '\x00')
338 strcpy(tmp_str, "No Name");
339
340 rtos->thread_details[tasks_found].thread_name_str =
341 (char *)malloc(strlen(tmp_str)+1);
342 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
343 rtos->thread_details[tasks_found].display_str = NULL;
344 rtos->thread_details[tasks_found].exists = true;
345
346 if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) {
347 char running_str[] = "Running";
348 rtos->thread_details[tasks_found].extra_info_str = (char *) malloc(
349 sizeof(running_str));
350 strcpy(rtos->thread_details[tasks_found].extra_info_str,
351 running_str);
352 } else
353 rtos->thread_details[tasks_found].extra_info_str = NULL;
354
355 tasks_found++;
356 list_thread_count--;
357
358 prev_list_elem_ptr = list_elem_ptr;
359 list_elem_ptr = 0;
360 retval = target_read_buffer(rtos->target,
361 prev_list_elem_ptr + param->list_elem_next_offset,
362 param->pointer_width,
363 (uint8_t *)&list_elem_ptr);
364 if (retval != ERROR_OK) {
365 LOG_ERROR("Error reading next thread item location in FreeRTOS thread list");
366 free(list_of_lists);
367 return retval;
368 }
369 }
370 }
371
372 free(list_of_lists);
373 rtos->thread_count = tasks_found;
374 return 0;
375 }
376
377 static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
378 {
379 int retval;
380 const struct FreeRTOS_params *param;
381 int64_t stack_ptr = 0;
382
383 *hex_reg_list = NULL;
384 if (rtos == NULL)
385 return -1;
386
387 if (thread_id == 0)
388 return -2;
389
390 if (rtos->rtos_specific_params == NULL)
391 return -1;
392
393 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
394
395 /* Read the stack pointer */
396 retval = target_read_buffer(rtos->target,
397 thread_id + param->thread_stack_offset,
398 param->pointer_width,
399 (uint8_t *)&stack_ptr);
400 if (retval != ERROR_OK) {
401 LOG_ERROR("Error reading stack frame from FreeRTOS thread");
402 return retval;
403 }
404
405 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
406 }
407
408 static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
409 {
410 unsigned int i;
411 *symbol_list = (symbol_table_elem_t *) malloc(
412 sizeof(symbol_table_elem_t) * ARRAY_SIZE(FreeRTOS_symbol_list));
413
414 for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++)
415 (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i];
416
417 return 0;
418 }
419
420 #if 0
421
422 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id)
423 {
424 return 0;
425 }
426
427 static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info)
428 {
429 int retval;
430 const struct FreeRTOS_params *param;
431
432 if (rtos == NULL)
433 return -1;
434
435 if (thread_id == 0)
436 return -2;
437
438 if (rtos->rtos_specific_params == NULL)
439 return -3;
440
441 param = (const struct FreeRTOS_params *) rtos->rtos_specific_params;
442
443 #define FREERTOS_THREAD_NAME_STR_SIZE (200)
444 char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE];
445
446 /* Read the thread name */
447 retval = target_read_buffer(rtos->target,
448 thread_id + param->thread_name_offset,
449 FREERTOS_THREAD_NAME_STR_SIZE,
450 (uint8_t *)&tmp_str);
451 if (retval != ERROR_OK) {
452 LOG_ERROR("Error reading first thread item location in FreeRTOS thread list");
453 return retval;
454 }
455 tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00';
456
457 if (tmp_str[0] == '\x00')
458 strcpy(tmp_str, "No Name");
459
460 *info = (char *)malloc(strlen(tmp_str)+1);
461 strcpy(*info, tmp_str);
462 return 0;
463 }
464
465 #endif
466
467 static int FreeRTOS_detect_rtos(struct target *target)
468 {
469 if ((target->rtos->symbols != NULL) &&
470 (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) {
471 /* looks like FreeRTOS */
472 return 1;
473 }
474 return 0;
475 }
476
477 static int FreeRTOS_create(struct target *target)
478 {
479 int i = 0;
480 while ((i < FREERTOS_NUM_PARAMS) &&
481 (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) {
482 i++;
483 }
484 if (i >= FREERTOS_NUM_PARAMS) {
485 LOG_ERROR("Could not find target in FreeRTOS compatibility list");
486 return -1;
487 }
488
489 target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i];
490 return 0;
491 }

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)