esirisc: support eSi-RISC targets
[openocd.git] / src / rtos / uCOS-III.c
1 /***************************************************************************
2 * Copyright (C) 2017 by Square, Inc. *
3 * Steven Stallion <stallion@squareup.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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/log.h>
24 #include <helper/time_support.h>
25 #include <helper/types.h>
26 #include <rtos/rtos.h>
27 #include <target/target.h>
28 #include <target/target_type.h>
29
30 #include "rtos_ucos_iii_stackings.h"
31
32 #ifndef UCOS_III_MAX_STRLEN
33 #define UCOS_III_MAX_STRLEN 64
34 #endif
35
36 #ifndef UCOS_III_MAX_THREADS
37 #define UCOS_III_MAX_THREADS 256
38 #endif
39
40 struct uCOS_III_params {
41 const char *target_name;
42 const unsigned char pointer_width;
43 symbol_address_t thread_stack_offset;
44 symbol_address_t thread_name_offset;
45 symbol_address_t thread_state_offset;
46 symbol_address_t thread_priority_offset;
47 symbol_address_t thread_prev_offset;
48 symbol_address_t thread_next_offset;
49 bool thread_offsets_updated;
50 size_t threadid_start;
51 const struct rtos_register_stacking *stacking_info;
52 size_t num_threads;
53 symbol_address_t threads[];
54 };
55
56 static const struct uCOS_III_params uCOS_III_params_list[] = {
57 {
58 "cortex_m", /* target_name */
59 sizeof(uint32_t), /* pointer_width */
60 0, /* thread_stack_offset */
61 0, /* thread_name_offset */
62 0, /* thread_state_offset */
63 0, /* thread_priority_offset */
64 0, /* thread_prev_offset */
65 0, /* thread_next_offset */
66 false, /* thread_offsets_updated */
67 1, /* threadid_start */
68 &rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */
69 0, /* num_threads */
70 },
71 {
72 "esirisc", /* target_name */
73 sizeof(uint32_t), /* pointer_width */
74 0, /* thread_stack_offset */
75 0, /* thread_name_offset */
76 0, /* thread_state_offset */
77 0, /* thread_priority_offset */
78 0, /* thread_prev_offset */
79 0, /* thread_next_offset */
80 false, /* thread_offsets_updated */
81 1, /* threadid_start */
82 &rtos_uCOS_III_eSi_RISC_stacking, /* stacking_info */
83 0, /* num_threads */
84 },
85 };
86
87 static const char * const uCOS_III_symbol_list[] = {
88 "OSRunning",
89 "OSTCBCurPtr",
90 "OSTaskDbgListPtr",
91 "OSTaskQty",
92
93 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
94 "openocd_OS_TCB_StkPtr_offset",
95 "openocd_OS_TCB_NamePtr_offset",
96 "openocd_OS_TCB_TaskState_offset",
97 "openocd_OS_TCB_Prio_offset",
98 "openocd_OS_TCB_DbgPrevPtr_offset",
99 "openocd_OS_TCB_DbgNextPtr_offset",
100 NULL
101 };
102
103 enum uCOS_III_symbol_values {
104 uCOS_III_VAL_OSRunning,
105 uCOS_III_VAL_OSTCBCurPtr,
106 uCOS_III_VAL_OSTaskDbgListPtr,
107 uCOS_III_VAL_OSTaskQty,
108
109 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
110 uCOS_III_VAL_OS_TCB_StkPtr_offset,
111 uCOS_III_VAL_OS_TCB_NamePtr_offset,
112 uCOS_III_VAL_OS_TCB_TaskState_offset,
113 uCOS_III_VAL_OS_TCB_Prio_offset,
114 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
115 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
116 };
117
118 static const char * const uCOS_III_thread_state_list[] = {
119 "Ready",
120 "Delay",
121 "Pend",
122 "Pend Timeout",
123 "Suspended",
124 "Delay Suspended",
125 "Pend Suspended",
126 "Pend Timeout Suspended",
127 };
128
129 static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
130 threadid_t *threadid)
131 {
132 struct uCOS_III_params *params = rtos->rtos_specific_params;
133 size_t thread_index;
134
135 for (thread_index = 0; thread_index < params->num_threads; thread_index++)
136 if (params->threads[thread_index] == thread_address)
137 goto found;
138
139 if (params->num_threads == UCOS_III_MAX_THREADS) {
140 LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
141 return ERROR_FAIL;
142 }
143
144 params->threads[thread_index] = thread_address;
145 params->num_threads++;
146 found:
147 *threadid = thread_index + params->threadid_start;
148 return ERROR_OK;
149 }
150
151 static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid,
152 symbol_address_t *thread_address)
153 {
154 struct uCOS_III_params *params = rtos->rtos_specific_params;
155 size_t thread_index;
156
157 thread_index = threadid - params->threadid_start;
158 if (thread_index >= params->num_threads) {
159 LOG_ERROR("uCOS-III: failed to find thread address");
160 return ERROR_FAIL;
161 }
162
163 *thread_address = params->threads[thread_index];
164 return ERROR_OK;
165 }
166
167 static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
168 {
169 struct uCOS_III_params *params = rtos->rtos_specific_params;
170 int retval;
171
172 /* read the thread list head */
173 symbol_address_t thread_list_address = 0;
174
175 retval = target_read_memory(rtos->target,
176 rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address,
177 params->pointer_width,
178 1,
179 (void *)&thread_list_address);
180 if (retval != ERROR_OK) {
181 LOG_ERROR("uCOS-III: failed to read thread list address");
182 return retval;
183 }
184
185 /* advance to end of thread list */
186 do {
187 *thread_address = thread_list_address;
188
189 retval = target_read_memory(rtos->target,
190 thread_list_address + params->thread_next_offset,
191 params->pointer_width,
192 1,
193 (void *)&thread_list_address);
194 if (retval != ERROR_OK) {
195 LOG_ERROR("uCOS-III: failed to read next thread address");
196 return retval;
197 }
198 } while (thread_list_address != 0);
199
200 return ERROR_OK;
201 }
202
203 static int uCOS_III_update_thread_offsets(struct rtos *rtos)
204 {
205 struct uCOS_III_params *params = rtos->rtos_specific_params;
206
207 if (params->thread_offsets_updated)
208 return ERROR_OK;
209
210 const struct thread_offset_map {
211 enum uCOS_III_symbol_values symbol_value;
212 symbol_address_t *thread_offset;
213 } thread_offset_maps[] = {
214 {
215 uCOS_III_VAL_OS_TCB_StkPtr_offset,
216 &params->thread_stack_offset,
217 },
218 {
219 uCOS_III_VAL_OS_TCB_NamePtr_offset,
220 &params->thread_name_offset,
221 },
222 {
223 uCOS_III_VAL_OS_TCB_TaskState_offset,
224 &params->thread_state_offset,
225 },
226 {
227 uCOS_III_VAL_OS_TCB_Prio_offset,
228 &params->thread_priority_offset,
229 },
230 {
231 uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset,
232 &params->thread_prev_offset,
233 },
234 {
235 uCOS_III_VAL_OS_TCB_DbgNextPtr_offset,
236 &params->thread_next_offset,
237 },
238 };
239
240 for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) {
241 const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i];
242
243 int retval = target_read_memory(rtos->target,
244 rtos->symbols[thread_offset_map->symbol_value].address,
245 params->pointer_width,
246 1,
247 (void *)thread_offset_map->thread_offset);
248 if (retval != ERROR_OK) {
249 LOG_ERROR("uCOS-III: failed to read thread offset");
250 return retval;
251 }
252 }
253
254 params->thread_offsets_updated = true;
255 return ERROR_OK;
256 }
257
258 static bool uCOS_III_detect_rtos(struct target *target)
259 {
260 return target->rtos->symbols != NULL &&
261 target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0;
262 }
263
264 static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
265 {
266 struct uCOS_III_params *params = target->rtos->rtos_specific_params;
267
268 params->thread_offsets_updated = false;
269 params->num_threads = 0;
270
271 return ERROR_OK;
272 }
273
274 static int uCOS_III_create(struct target *target)
275 {
276 struct uCOS_III_params *params;
277
278 for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++)
279 if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) {
280 params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads)));
281 if (params == NULL) {
282 LOG_ERROR("uCOS-III: out of memory");
283 return ERROR_FAIL;
284 }
285
286 memcpy(params, &uCOS_III_params_list[i], sizeof(uCOS_III_params_list[i]));
287 target->rtos->rtos_specific_params = (void *)params;
288
289 target_register_reset_callback(uCOS_III_reset_handler, NULL);
290
291 return ERROR_OK;
292 }
293
294 LOG_ERROR("uCOS-III: target not supported: %s", target->type->name);
295 return ERROR_FAIL;
296 }
297
298 static int uCOS_III_update_threads(struct rtos *rtos)
299 {
300 struct uCOS_III_params *params = rtos->rtos_specific_params;
301 int retval;
302
303 /* free previous thread details */
304 rtos_free_threadlist(rtos);
305
306 /* verify RTOS is running */
307 uint8_t rtos_running;
308
309 retval = target_read_u8(rtos->target,
310 rtos->symbols[uCOS_III_VAL_OSRunning].address,
311 &rtos_running);
312 if (retval != ERROR_OK) {
313 LOG_ERROR("uCOS-III: failed to read RTOS running");
314 return retval;
315 }
316
317 if (rtos_running != 1 && rtos_running != 0) {
318 LOG_ERROR("uCOS-III: invalid RTOS running value");
319 return ERROR_FAIL;
320 }
321
322 if (!rtos_running) {
323 rtos->thread_details = calloc(1, sizeof(struct thread_detail));
324 if (rtos->thread_details == NULL) {
325 LOG_ERROR("uCOS-III: out of memory");
326 return ERROR_FAIL;
327 }
328
329 rtos->thread_count = 1;
330 rtos->thread_details->threadid = 0;
331 rtos->thread_details->exists = true;
332 rtos->current_thread = 0;
333
334 return ERROR_OK;
335 }
336
337 /* update thread offsets */
338 retval = uCOS_III_update_thread_offsets(rtos);
339 if (retval != ERROR_OK) {
340 LOG_ERROR("uCOS-III: failed to update thread offsets");
341 return retval;
342 }
343
344 /* read current thread address */
345 symbol_address_t current_thread_address = 0;
346
347 retval = target_read_memory(rtos->target,
348 rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address,
349 params->pointer_width,
350 1,
351 (void *)&current_thread_address);
352 if (retval != ERROR_OK) {
353 LOG_ERROR("uCOS-III: failed to read current thread address");
354 return retval;
355 }
356
357 /* read number of tasks */
358 retval = target_read_u16(rtos->target,
359 rtos->symbols[uCOS_III_VAL_OSTaskQty].address,
360 (void *)&rtos->thread_count);
361 if (retval != ERROR_OK) {
362 LOG_ERROR("uCOS-III: failed to read thread count");
363 return retval;
364 }
365
366 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
367 if (rtos->thread_details == NULL) {
368 LOG_ERROR("uCOS-III: out of memory");
369 return ERROR_FAIL;
370 }
371
372 /*
373 * uC/OS-III adds tasks in LIFO order; advance to the end of the
374 * list and work backwards to preserve the intended order.
375 */
376 symbol_address_t thread_address = 0;
377
378 retval = uCOS_III_find_last_thread_address(rtos, &thread_address);
379 if (retval != ERROR_OK) {
380 LOG_ERROR("uCOS-III: failed to find last thread address");
381 return retval;
382 }
383
384 for (int i = 0; i < rtos->thread_count; i++) {
385 struct thread_detail *thread_detail = &rtos->thread_details[i];
386 char thread_str_buffer[UCOS_III_MAX_STRLEN + 1];
387
388 /* find or create new threadid */
389 retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid);
390 if (retval != ERROR_OK) {
391 LOG_ERROR("uCOS-III: failed to find or create thread");
392 return retval;
393 }
394
395 if (thread_address == current_thread_address)
396 rtos->current_thread = thread_detail->threadid;
397
398 thread_detail->exists = true;
399
400 /* read thread name */
401 symbol_address_t thread_name_address = 0;
402
403 retval = target_read_memory(rtos->target,
404 thread_address + params->thread_name_offset,
405 params->pointer_width,
406 1,
407 (void *)&thread_name_address);
408 if (retval != ERROR_OK) {
409 LOG_ERROR("uCOS-III: failed to name address");
410 return retval;
411 }
412
413 retval = target_read_buffer(rtos->target,
414 thread_name_address,
415 sizeof(thread_str_buffer),
416 (void *)thread_str_buffer);
417 if (retval != ERROR_OK) {
418 LOG_ERROR("uCOS-III: failed to read thread name");
419 return retval;
420 }
421
422 thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0';
423 thread_detail->thread_name_str = strdup(thread_str_buffer);
424
425 /* read thread extra info */
426 uint8_t thread_state;
427 uint8_t thread_priority;
428
429 retval = target_read_u8(rtos->target,
430 thread_address + params->thread_state_offset,
431 &thread_state);
432 if (retval != ERROR_OK) {
433 LOG_ERROR("uCOS-III: failed to read thread state");
434 return retval;
435 }
436
437 retval = target_read_u8(rtos->target,
438 thread_address + params->thread_priority_offset,
439 &thread_priority);
440 if (retval != ERROR_OK) {
441 LOG_ERROR("uCOS-III: failed to read thread priority");
442 return retval;
443 }
444
445 const char *thread_state_str;
446
447 if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list))
448 thread_state_str = uCOS_III_thread_state_list[thread_state];
449 else
450 thread_state_str = "Unknown";
451
452 snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d",
453 thread_state_str, thread_priority);
454 thread_detail->extra_info_str = strdup(thread_str_buffer);
455
456 /* read previous thread address */
457 retval = target_read_memory(rtos->target,
458 thread_address + params->thread_prev_offset,
459 params->pointer_width,
460 1,
461 (void *)&thread_address);
462 if (retval != ERROR_OK) {
463 LOG_ERROR("uCOS-III: failed to read previous thread address");
464 return retval;
465 }
466 }
467
468 return ERROR_OK;
469 }
470
471 static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
472 struct rtos_reg **reg_list, int *num_regs)
473 {
474 struct uCOS_III_params *params = rtos->rtos_specific_params;
475 int retval;
476
477 /* find thread address for threadid */
478 symbol_address_t thread_address = 0;
479
480 retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address);
481 if (retval != ERROR_OK) {
482 LOG_ERROR("uCOS-III: failed to find thread address");
483 return retval;
484 }
485
486 /* read thread stack address */
487 symbol_address_t stack_address = 0;
488
489 retval = target_read_memory(rtos->target,
490 thread_address + params->thread_stack_offset,
491 params->pointer_width,
492 1,
493 (void *)&stack_address);
494 if (retval != ERROR_OK) {
495 LOG_ERROR("uCOS-III: failed to read stack address");
496 return retval;
497 }
498
499 return rtos_generic_stack_read(rtos->target,
500 params->stacking_info,
501 stack_address,
502 reg_list,
503 num_regs);
504 }
505
506 static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
507 {
508 *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t));
509 if (*symbol_list == NULL) {
510 LOG_ERROR("uCOS-III: out of memory");
511 return ERROR_FAIL;
512 }
513
514 for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++)
515 (*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i];
516
517 return ERROR_OK;
518 }
519
520 const struct rtos_type uCOS_III_rtos = {
521 .name = "uCOS-III",
522 .detect_rtos = uCOS_III_detect_rtos,
523 .create = uCOS_III_create,
524 .update_threads = uCOS_III_update_threads,
525 .get_thread_reg_list = uCOS_III_get_thread_reg_list,
526 .get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup,
527 };

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)