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