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

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)