1 /***************************************************************************
2 * Copyright (C) 2017 by Square, Inc. *
3 * Steven Stallion <stallion@squareup.com> *
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. *
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. *
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 ***************************************************************************/
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>
30 #include "rtos_ucos_iii_stackings.h"
32 #ifndef UCOS_III_MAX_STRLEN
33 #define UCOS_III_MAX_STRLEN 64
36 #ifndef UCOS_III_MAX_THREADS
37 #define UCOS_III_MAX_THREADS 256
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
;
53 symbol_address_t threads
[];
56 static const struct ucos_iii_params ucos_iii_params_list
[] = {
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 */
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 */
87 static const char * const ucos_iii_symbol_list
[] = {
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",
103 enum ucos_iii_symbol_values
{
104 UCOS_III_VAL_OS_RUNNING
,
105 UCOS_III_VAL_OS_TCB_CUR_PTR
,
106 UCOS_III_VAL_OS_TASK_DBG_LIST_PTR
,
107 UCOS_III_VAL_OS_TASK_QTY
,
109 /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */
110 UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET
,
111 UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET
,
112 UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET
,
113 UCOS_III_VAL_OS_TCB_PRIO_OFFSET
,
114 UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET
,
115 UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET
,
118 static const char * const ucos_iii_thread_state_list
[] = {
126 "Pend Timeout Suspended",
129 static int ucos_iii_find_or_create_thread(struct rtos
*rtos
, symbol_address_t thread_address
,
130 threadid_t
*threadid
)
132 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
135 for (thread_index
= 0; thread_index
< params
->num_threads
; thread_index
++)
136 if (params
->threads
[thread_index
] == thread_address
)
139 if (params
->num_threads
== UCOS_III_MAX_THREADS
) {
140 LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS");
144 params
->threads
[thread_index
] = thread_address
;
145 params
->num_threads
++;
147 *threadid
= thread_index
+ params
->threadid_start
;
151 static int ucos_iii_find_thread_address(struct rtos
*rtos
, threadid_t threadid
,
152 symbol_address_t
*thread_address
)
154 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
157 thread_index
= threadid
- params
->threadid_start
;
158 if (thread_index
>= params
->num_threads
) {
159 LOG_ERROR("uCOS-III: failed to find thread address");
163 *thread_address
= params
->threads
[thread_index
];
167 static int ucos_iii_find_last_thread_address(struct rtos
*rtos
, symbol_address_t
*thread_address
)
169 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
172 /* read the thread list head */
173 symbol_address_t thread_list_address
= 0;
175 retval
= target_read_memory(rtos
->target
,
176 rtos
->symbols
[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR
].address
,
177 params
->pointer_width
,
179 (void *)&thread_list_address
);
180 if (retval
!= ERROR_OK
) {
181 LOG_ERROR("uCOS-III: failed to read thread list address");
185 /* advance to end of thread list */
187 *thread_address
= thread_list_address
;
189 retval
= target_read_memory(rtos
->target
,
190 thread_list_address
+ params
->thread_next_offset
,
191 params
->pointer_width
,
193 (void *)&thread_list_address
);
194 if (retval
!= ERROR_OK
) {
195 LOG_ERROR("uCOS-III: failed to read next thread address");
198 } while (thread_list_address
!= 0);
203 static int ucos_iii_update_thread_offsets(struct rtos
*rtos
)
205 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
207 if (params
->thread_offsets_updated
)
210 const struct thread_offset_map
{
211 enum ucos_iii_symbol_values symbol_value
;
212 symbol_address_t
*thread_offset
;
213 } thread_offset_maps
[] = {
215 UCOS_III_VAL_OS_TCB_STK_PTR_OFFSET
,
216 ¶ms
->thread_stack_offset
,
219 UCOS_III_VAL_OS_TCB_NAME_PTR_OFFSET
,
220 ¶ms
->thread_name_offset
,
223 UCOS_III_VAL_OS_TCB_TASK_STATE_OFFSET
,
224 ¶ms
->thread_state_offset
,
227 UCOS_III_VAL_OS_TCB_PRIO_OFFSET
,
228 ¶ms
->thread_priority_offset
,
231 UCOS_III_VAL_OS_TCB_DBG_PREV_PTR_OFFSET
,
232 ¶ms
->thread_prev_offset
,
235 UCOS_III_VAL_OS_TCB_DBG_NEXT_PTR_OFFSET
,
236 ¶ms
->thread_next_offset
,
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
];
243 int retval
= target_read_memory(rtos
->target
,
244 rtos
->symbols
[thread_offset_map
->symbol_value
].address
,
245 params
->pointer_width
,
247 (void *)thread_offset_map
->thread_offset
);
248 if (retval
!= ERROR_OK
) {
249 LOG_ERROR("uCOS-III: failed to read thread offset");
254 params
->thread_offsets_updated
= true;
258 static bool ucos_iii_detect_rtos(struct target
*target
)
260 return target
->rtos
->symbols
&&
261 target
->rtos
->symbols
[UCOS_III_VAL_OS_RUNNING
].address
!= 0;
264 static int ucos_iii_reset_handler(struct target
*target
, enum target_reset_mode reset_mode
, void *priv
)
266 struct ucos_iii_params
*params
= target
->rtos
->rtos_specific_params
;
268 params
->thread_offsets_updated
= false;
269 params
->num_threads
= 0;
274 static int ucos_iii_create(struct target
*target
)
276 struct ucos_iii_params
*params
;
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
)));
282 LOG_ERROR("uCOS-III: out of memory");
286 memcpy(params
, &ucos_iii_params_list
[i
], sizeof(ucos_iii_params_list
[i
]));
287 target
->rtos
->rtos_specific_params
= (void *)params
;
289 target_register_reset_callback(ucos_iii_reset_handler
, NULL
);
294 LOG_ERROR("uCOS-III: target not supported: %s", target
->type
->name
);
298 static int ucos_iii_update_threads(struct rtos
*rtos
)
300 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
303 if (!rtos
->symbols
) {
304 LOG_ERROR("uCOS-III: symbol list not loaded");
308 /* free previous thread details */
309 rtos_free_threadlist(rtos
);
311 /* verify RTOS is running */
312 uint8_t rtos_running
;
314 retval
= target_read_u8(rtos
->target
,
315 rtos
->symbols
[UCOS_III_VAL_OS_RUNNING
].address
,
317 if (retval
!= ERROR_OK
) {
318 LOG_ERROR("uCOS-III: failed to read RTOS running");
322 if (rtos_running
!= 1 && rtos_running
!= 0) {
323 LOG_ERROR("uCOS-III: invalid RTOS running value");
328 rtos
->thread_details
= calloc(1, sizeof(struct thread_detail
));
329 if (!rtos
->thread_details
) {
330 LOG_ERROR("uCOS-III: out of memory");
334 rtos
->thread_count
= 1;
335 rtos
->thread_details
->threadid
= 0;
336 rtos
->thread_details
->exists
= true;
337 rtos
->current_thread
= 0;
342 /* update thread offsets */
343 retval
= ucos_iii_update_thread_offsets(rtos
);
344 if (retval
!= ERROR_OK
) {
345 LOG_ERROR("uCOS-III: failed to update thread offsets");
349 /* read current thread address */
350 symbol_address_t current_thread_address
= 0;
352 retval
= target_read_memory(rtos
->target
,
353 rtos
->symbols
[UCOS_III_VAL_OS_TCB_CUR_PTR
].address
,
354 params
->pointer_width
,
356 (void *)¤t_thread_address
);
357 if (retval
!= ERROR_OK
) {
358 LOG_ERROR("uCOS-III: failed to read current thread address");
362 /* read number of tasks */
363 retval
= target_read_u16(rtos
->target
,
364 rtos
->symbols
[UCOS_III_VAL_OS_TASK_QTY
].address
,
365 (void *)&rtos
->thread_count
);
366 if (retval
!= ERROR_OK
) {
367 LOG_ERROR("uCOS-III: failed to read thread count");
371 rtos
->thread_details
= calloc(rtos
->thread_count
, sizeof(struct thread_detail
));
372 if (!rtos
->thread_details
) {
373 LOG_ERROR("uCOS-III: out of memory");
378 * uC/OS-III adds tasks in LIFO order; advance to the end of the
379 * list and work backwards to preserve the intended order.
381 symbol_address_t thread_address
= 0;
383 retval
= ucos_iii_find_last_thread_address(rtos
, &thread_address
);
384 if (retval
!= ERROR_OK
) {
385 LOG_ERROR("uCOS-III: failed to find last thread address");
389 for (int i
= 0; i
< rtos
->thread_count
; i
++) {
390 struct thread_detail
*thread_detail
= &rtos
->thread_details
[i
];
391 char thread_str_buffer
[UCOS_III_MAX_STRLEN
+ 1];
393 /* find or create new threadid */
394 retval
= ucos_iii_find_or_create_thread(rtos
, thread_address
, &thread_detail
->threadid
);
395 if (retval
!= ERROR_OK
) {
396 LOG_ERROR("uCOS-III: failed to find or create thread");
400 if (thread_address
== current_thread_address
)
401 rtos
->current_thread
= thread_detail
->threadid
;
403 thread_detail
->exists
= true;
405 /* read thread name */
406 symbol_address_t thread_name_address
= 0;
408 retval
= target_read_memory(rtos
->target
,
409 thread_address
+ params
->thread_name_offset
,
410 params
->pointer_width
,
412 (void *)&thread_name_address
);
413 if (retval
!= ERROR_OK
) {
414 LOG_ERROR("uCOS-III: failed to name address");
418 retval
= target_read_buffer(rtos
->target
,
420 sizeof(thread_str_buffer
),
421 (void *)thread_str_buffer
);
422 if (retval
!= ERROR_OK
) {
423 LOG_ERROR("uCOS-III: failed to read thread name");
427 thread_str_buffer
[sizeof(thread_str_buffer
) - 1] = '\0';
428 thread_detail
->thread_name_str
= strdup(thread_str_buffer
);
430 /* read thread extra info */
431 uint8_t thread_state
;
432 uint8_t thread_priority
;
434 retval
= target_read_u8(rtos
->target
,
435 thread_address
+ params
->thread_state_offset
,
437 if (retval
!= ERROR_OK
) {
438 LOG_ERROR("uCOS-III: failed to read thread state");
442 retval
= target_read_u8(rtos
->target
,
443 thread_address
+ params
->thread_priority_offset
,
445 if (retval
!= ERROR_OK
) {
446 LOG_ERROR("uCOS-III: failed to read thread priority");
450 const char *thread_state_str
;
452 if (thread_state
< ARRAY_SIZE(ucos_iii_thread_state_list
))
453 thread_state_str
= ucos_iii_thread_state_list
[thread_state
];
455 thread_state_str
= "Unknown";
457 snprintf(thread_str_buffer
, sizeof(thread_str_buffer
), "State: %s, Priority: %d",
458 thread_state_str
, thread_priority
);
459 thread_detail
->extra_info_str
= strdup(thread_str_buffer
);
461 /* read previous thread address */
462 retval
= target_read_memory(rtos
->target
,
463 thread_address
+ params
->thread_prev_offset
,
464 params
->pointer_width
,
466 (void *)&thread_address
);
467 if (retval
!= ERROR_OK
) {
468 LOG_ERROR("uCOS-III: failed to read previous thread address");
476 static int ucos_iii_get_thread_reg_list(struct rtos
*rtos
, threadid_t threadid
,
477 struct rtos_reg
**reg_list
, int *num_regs
)
479 struct ucos_iii_params
*params
= rtos
->rtos_specific_params
;
482 /* find thread address for threadid */
483 symbol_address_t thread_address
= 0;
485 retval
= ucos_iii_find_thread_address(rtos
, threadid
, &thread_address
);
486 if (retval
!= ERROR_OK
) {
487 LOG_ERROR("uCOS-III: failed to find thread address");
491 /* read thread stack address */
492 symbol_address_t stack_address
= 0;
494 retval
= target_read_memory(rtos
->target
,
495 thread_address
+ params
->thread_stack_offset
,
496 params
->pointer_width
,
498 (void *)&stack_address
);
499 if (retval
!= ERROR_OK
) {
500 LOG_ERROR("uCOS-III: failed to read stack address");
504 return rtos_generic_stack_read(rtos
->target
,
505 params
->stacking_info
,
511 static int ucos_iii_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
513 *symbol_list
= calloc(ARRAY_SIZE(ucos_iii_symbol_list
), sizeof(struct symbol_table_elem
));
515 LOG_ERROR("uCOS-III: out of memory");
519 for (size_t i
= 0; i
< ARRAY_SIZE(ucos_iii_symbol_list
); i
++)
520 (*symbol_list
)[i
].symbol_name
= ucos_iii_symbol_list
[i
];
525 const struct rtos_type ucos_iii_rtos
= {
527 .detect_rtos
= ucos_iii_detect_rtos
,
528 .create
= ucos_iii_create
,
529 .update_threads
= ucos_iii_update_threads
,
530 .get_thread_reg_list
= ucos_iii_get_thread_reg_list
,
531 .get_symbol_list_to_lookup
= ucos_iii_get_symbol_list_to_lookup
,