diff options
author | Palmer Dabbelt <palmer@dabbelt.com> | 2017-06-14 17:02:04 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-14 17:02:04 -0700 |
commit | ecc181d12d3b876d39b67b354e497f1fbe514a3f (patch) | |
tree | c6e676de5faa37d52544c5fe120f747bf225d38c /src/rtos | |
parent | 7af58e6283c8e7d350b6b55c93a1d326326ed831 (diff) | |
parent | 64af05291132811288d7af32c9fd27e254778d5c (diff) | |
download | riscv-openocd-ecc181d12d3b876d39b67b354e497f1fbe514a3f.zip riscv-openocd-ecc181d12d3b876d39b67b354e497f1fbe514a3f.tar.gz riscv-openocd-ecc181d12d3b876d39b67b354e497f1fbe514a3f.tar.bz2 |
Merge pull request #62 from riscv/riscv64
Merge mainline OpenOCD
Diffstat (limited to 'src/rtos')
-rw-r--r-- | src/rtos/ChibiOS.c | 6 | ||||
-rw-r--r-- | src/rtos/FreeRTOS.c | 2 | ||||
-rw-r--r-- | src/rtos/Makefile.am | 56 | ||||
-rw-r--r-- | src/rtos/ThreadX.c | 4 | ||||
-rw-r--r-- | src/rtos/eCos.c | 4 | ||||
-rw-r--r-- | src/rtos/embKernel.c | 6 | ||||
-rw-r--r-- | src/rtos/linux.c | 13 | ||||
-rw-r--r-- | src/rtos/mqx.c | 10 | ||||
-rw-r--r-- | src/rtos/rtos.c | 45 | ||||
-rw-r--r-- | src/rtos/rtos_ucos_iii_stackings.c | 53 | ||||
-rw-r--r-- | src/rtos/rtos_ucos_iii_stackings.h | 30 | ||||
-rw-r--r-- | src/rtos/uCOS-III.c | 509 |
12 files changed, 675 insertions, 63 deletions
diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index 00e9df7..1bc1af8 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -440,11 +440,11 @@ static int ChibiOS_update_threads(struct rtos *rtos) if (threadState < CHIBIOS_NUM_STATES) state_desc = ChibiOS_thread_states[threadState]; else - state_desc = "Unknown state"; + state_desc = "Unknown"; curr_thrd_details->extra_info_str = malloc(strlen( - state_desc)+1); - strcpy(curr_thrd_details->extra_info_str, state_desc); + state_desc)+8); + sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc); curr_thrd_details->exists = true; diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 52cebad..83961eb 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -362,7 +362,7 @@ static int FreeRTOS_update_threads(struct rtos *rtos) rtos->thread_details[tasks_found].exists = true; if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) { - char running_str[] = "Running"; + char running_str[] = "State: Running"; rtos->thread_details[tasks_found].extra_info_str = malloc( sizeof(running_str)); strcpy(rtos->thread_details[tasks_found].extra_info_str, diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index a7dab00..22f7da5 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -1,32 +1,34 @@ -# *************************************************************************** -# * Copyright (C) 2011 by Broadcom Corporation * -# * Evan Hunter - ehunter@broadcom.com * -# * * -# * This program is free software; you can redistribute it and/or modify * -# * it under the terms of the GNU General Public License as published by * -# * the Free Software Foundation; either version 2 of the License, or * -# * (at your option) any later version. * -# * * -# * This program is distributed in the hope that it will be useful, * -# * but WITHOUT ANY WARRANTY; without even the implied warranty of * -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -# * GNU General Public License for more details. * -# * * -# * You should have received a copy of the GNU General Public License * -# * along with this program. If not, see <http://www.gnu.org/licenses/>. * -# *************************************************************************** +noinst_LTLIBRARIES += %D%/librtos.la +%C%_librtos_la_SOURCES = \ + %D%/rtos.c \ + %D%/rtos_standard_stackings.c \ + %D%/rtos_ecos_stackings.c \ + %D%/rtos_chibios_stackings.c \ + %D%/rtos_embkernel_stackings.c \ + %D%/rtos_mqx_stackings.c \ + %D%/rtos_ucos_iii_stackings.c \ + %D%/FreeRTOS.c \ + %D%/ThreadX.c \ + %D%/eCos.c \ + %D%/linux.c \ + %D%/ChibiOS.c \ + %D%/embKernel.c \ + %D%/mqx.c \ + %D%/riscv_debug.c \ + %D%/uCOS-III.c \ + %D%/rtos.h \ + %D%/rtos_standard_stackings.h \ + %D%/rtos_ecos_stackings.h \ + %D%/linux_header.h \ + %D%/rtos_chibios_stackings.h \ + %D%/rtos_embkernel_stackings.h \ + %D%/rtos_mqx_stackings.h \ + %D%/rtos_ucos_iii_stackings.h \ + %D%/riscv_debug.h -include $(top_srcdir)/common.mk +%C%_librtos_la_CFLAGS = $(AM_CFLAGS) -METASOURCES = AUTO -noinst_LTLIBRARIES = librtos.la -noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h rtos_embkernel_stackings.h rtos_mqx_stackings.h riscv_debug.h -librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c rtos_chibios_stackings.c rtos_embkernel_stackings.c rtos_mqx_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c embKernel.c mqx.c riscv_debug.c - -librtos_la_CFLAGS = if IS_MINGW # FD_* macros are sloppy with their signs on MinGW32 platform -librtos_la_CFLAGS += -Wno-sign-compare +%C%_librtos_la_CFLAGS += -Wno-sign-compare endif - -MAINTAINERCLEANFILES = $(srcdir)/Makefile.in diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 8267b9f..ab8a66e 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -408,8 +408,8 @@ static int ThreadX_update_threads(struct rtos *rtos) state_desc = "Unknown state"; rtos->thread_details[tasks_found].extra_info_str = malloc(strlen( - state_desc)+1); - strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc); + state_desc)+8); + sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc); rtos->thread_details[tasks_found].exists = true; diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index e38e11f..edc3d8b 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -261,8 +261,8 @@ static int eCos_update_threads(struct rtos *rtos) state_desc = "Unknown state"; rtos->thread_details[tasks_found].extra_info_str = malloc(strlen( - state_desc)+1); - strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc); + state_desc)+8); + sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc); rtos->thread_details[tasks_found].exists = true; diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index ceb313f..e515383 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -168,11 +168,11 @@ static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, cons return retval; details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE); if (task == rtos->current_thread) { - snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running", + snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u", (unsigned int) priority); } else { - snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority, - state_str); + snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u", + state_str, (unsigned int) priority); } LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable, diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 8c150af..3efaab1 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -105,11 +105,11 @@ static int linux_os_dummy_update(struct rtos *rtos) return 0; } -static int linux_compute_virt2phys(struct target *target, uint32_t address) +static int linux_compute_virt2phys(struct target *target, target_addr_t address) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; - uint32_t pa = 0; + target_addr_t pa = 0; int retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) { LOG_ERROR("Cannot compute linux virt2phys translation"); @@ -1213,7 +1213,7 @@ int linux_thread_extra_info(struct target *target, if (temp->threadid == threadid) { char *pid = " PID: "; char *pid_current = "*PID: "; - char *name = "NAME: "; + char *name = "Name: "; int str_size = strlen(pid) + strlen(name); char *tmp_str = calloc(1, str_size + 50); char *tmp_str_ptr = tmp_str; @@ -1225,13 +1225,12 @@ int linux_thread_extra_info(struct target *target, else tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid); - tmp_str_ptr += - sprintf(tmp_str_ptr, "%d", (int)temp->pid); - tmp_str_ptr += sprintf(tmp_str_ptr, "%s", " | "); + tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid); sprintf(tmp_str_ptr, "%s", name); sprintf(tmp_str_ptr, "%s", temp->name); char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1); - int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1); + size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str, + strlen(tmp_str), strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index b8095a0..63a48c5 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -353,7 +353,7 @@ static int mqx_update_threads( uint32_t task_name_addr = 0, task_id = 0, task_errno = 0; uint32_t state_index = 0, state_max = 0; uint32_t extra_info_length = 0; - char *state_name = "unknown state"; + char *state_name = "Unknown"; /* set current taskpool address */ if (ERROR_OK != mqx_get_member( @@ -435,13 +435,13 @@ static int mqx_update_threads( * calculate length as: * state length + address length + errno length + formatter length */ - extra_info_length += strlen((void *)state_name) + 8 + 8 + 8; + extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8; rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1); if (NULL == rtos->thread_details[i].extra_info_str) return ERROR_FAIL; - snprintf( - rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32, - state_name, task_addr, task_errno + snprintf(rtos->thread_details[i].extra_info_str, extra_info_length, + "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32, + state_name, task_addr, task_errno ); /* set active thread */ if (active_td_addr == task_addr) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 9bf218e..5e8ce48 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -34,6 +34,7 @@ extern struct rtos_type Linux_os; extern struct rtos_type ChibiOS_rtos; extern struct rtos_type embKernel_rtos; extern struct rtos_type mqx_rtos; +extern struct rtos_type uCOS_III_rtos; extern struct rtos_type riscv_rtos; static struct rtos_type *rtos_types[] = { @@ -44,6 +45,7 @@ static struct rtos_type *rtos_types[] = { &ChibiOS_rtos, &embKernel_rtos, &mqx_rtos, + &uCOS_III_rtos, &riscv_rtos, NULL }; @@ -107,6 +109,7 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) int x; const char *cp; struct Jim_Obj *res; + int e; if (!goi->isconfigure && goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); @@ -115,7 +118,9 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target) os_free(target); - Jim_GetOpt_String(goi, &cp, NULL); + e = Jim_GetOpt_String(goi, &cp, NULL); + if (e != JIM_OK) + return e; if (0 == strcmp(cp, "auto")) { /* Auto detect tries to look up all symbols for each RTOS, @@ -216,7 +221,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s goto done; /* Decode any symbol name in the packet*/ - int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); + size_t len = unhexify((uint8_t *)cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ @@ -264,7 +269,9 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s } reply_len = snprintf(reply, sizeof(reply), "qSymbol:"); - reply_len += hexify(reply + reply_len, next_sym->symbol_name, 0, sizeof(reply) - reply_len); + reply_len += hexify(reply + reply_len, + (const uint8_t *)next_sym->symbol_name, strlen(next_sym->symbol_name), + sizeof(reply) - reply_len); done: gdb_put_packet(connection, reply, reply_len); @@ -304,14 +311,14 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa if (detail->extra_info_str != NULL) str_size += strlen(detail->extra_info_str); - char *tmp_str = calloc(str_size + 4, sizeof(char)); + char *tmp_str = calloc(str_size + 9, sizeof(char)); char *tmp_str_ptr = tmp_str; if (detail->thread_name_str != NULL) - tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str); + tmp_str_ptr += sprintf(tmp_str_ptr, "Name: %s", detail->thread_name_str); if (detail->extra_info_str != NULL) { if (tmp_str_ptr != tmp_str) - tmp_str_ptr += sprintf(tmp_str_ptr, " : "); + tmp_str_ptr += sprintf(tmp_str_ptr, ", "); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->extra_info_str); } @@ -319,7 +326,8 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa (size_t) (tmp_str_ptr - tmp_str)); char *hex_str = malloc(strlen(tmp_str) * 2 + 1); - int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1); + size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str, + strlen(tmp_str), strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); @@ -400,9 +408,14 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ if ((packet[1] == 'g') && (target->rtos != NULL)) { - sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid); - LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64 "\r\n", - target->rtos->current_threadid); + threadid_t threadid; + sscanf(packet, "Hg%16" SCNx64, &threadid); + LOG_DEBUG("RTOS: GDB requested to set current thread to 0x%" PRIx64, threadid); + /* threadid of 0 indicates target should choose */ + if (threadid == 0) + target->rtos->current_threadid = target->rtos->current_thread; + else + target->rtos->current_threadid = threadid; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; @@ -426,9 +439,13 @@ int rtos_get_gdb_reg_list(struct connection *connection) current_threadid, target->rtos->current_thread); - target->rtos->type->get_thread_reg_list(target->rtos, - current_threadid, - &hex_reg_list); + int retval = target->rtos->type->get_thread_reg_list(target->rtos, + current_threadid, + &hex_reg_list); + if (retval != ERROR_OK) { + LOG_ERROR("RTOS: failed to get register list"); + return retval; + } if (hex_reg_list != NULL) { gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); @@ -546,5 +563,7 @@ void rtos_free_threadlist(struct rtos *rtos) free(rtos->thread_details); rtos->thread_details = NULL; rtos->thread_count = 0; + rtos->current_threadid = -1; + rtos->current_thread = 0; } } diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c new file mode 100644 index 0000000..f2f5564 --- /dev/null +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2016 by Square, Inc. * + * Steven Stallion <stallion@squareup.com> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtos.h" +#include "rtos_standard_stackings.h" +#include "target/armv7m.h" + +static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = { + { 0x20, 32 }, /* r0 */ + { 0x24, 32 }, /* r1 */ + { 0x28, 32 }, /* r2 */ + { 0x2c, 32 }, /* r3 */ + { 0x00, 32 }, /* r4 */ + { 0x04, 32 }, /* r5 */ + { 0x08, 32 }, /* r6 */ + { 0x0c, 32 }, /* r7 */ + { 0x10, 32 }, /* r8 */ + { 0x14, 32 }, /* r9 */ + { 0x18, 32 }, /* r10 */ + { 0x1c, 32 }, /* r11 */ + { 0x30, 32 }, /* r12 */ + { -2, 32 }, /* sp */ + { 0x34, 32 }, /* lr */ + { 0x38, 32 }, /* pc */ + { 0x3c, 32 }, /* xPSR */ +}; + +const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { + 0x40, /* stack_registers_size */ + -1, /* stack_growth_direction */ + ARMV7M_NUM_CORE_REGS, /* num_output_registers */ + rtos_generic_stack_align8, /* stack_alignment */ + rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ +}; diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h new file mode 100644 index 0000000..c462cd7 --- /dev/null +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2016 by Square, Inc. * + * Steven Stallion <stallion@squareup.com> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H +#define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rtos.h" + +extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking; + +#endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */ diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c new file mode 100644 index 0000000..75cfe52 --- /dev/null +++ b/src/rtos/uCOS-III.c @@ -0,0 +1,509 @@ +/*************************************************************************** + * Copyright (C) 2016 by Square, Inc. * + * Steven Stallion <stallion@squareup.com> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <jtag/jtag.h> +#include "target/target.h" +#include "target/target_type.h" +#include "rtos.h" +#include "helper/log.h" +#include "helper/types.h" +#include "rtos/rtos_ucos_iii_stackings.h" + +#ifndef UCOS_III_MAX_STRLEN +#define UCOS_III_MAX_STRLEN 64 +#endif + +#ifndef UCOS_III_MAX_THREADS +#define UCOS_III_MAX_THREADS 256 +#endif + +struct uCOS_III_params { + const char *target_name; + const unsigned char pointer_width; + symbol_address_t thread_stack_offset; + symbol_address_t thread_name_offset; + symbol_address_t thread_state_offset; + symbol_address_t thread_priority_offset; + symbol_address_t thread_prev_offset; + symbol_address_t thread_next_offset; + bool thread_offsets_updated; + size_t threadid_start; + const struct rtos_register_stacking *stacking_info; + size_t num_threads; + symbol_address_t threads[]; +}; + +static const struct uCOS_III_params uCOS_III_params_list[] = { + { + "cortex_m", /* target_name */ + sizeof(uint32_t), /* pointer_width */ + 0, /* thread_stack_offset */ + 0, /* thread_name_offset */ + 0, /* thread_state_offset */ + 0, /* thread_priority_offset */ + 0, /* thread_prev_offset */ + 0, /* thread_next_offset */ + false, /* thread_offsets_updated */ + 1, /* threadid_start */ + &rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */ + 0, /* num_threads */ + }, +}; + +static const char * const uCOS_III_symbol_list[] = { + "OSRunning", + "OSTCBCurPtr", + "OSTaskDbgListPtr", + "OSTaskQty", + + /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */ + "openocd_OS_TCB_StkPtr_offset", + "openocd_OS_TCB_NamePtr_offset", + "openocd_OS_TCB_TaskState_offset", + "openocd_OS_TCB_Prio_offset", + "openocd_OS_TCB_DbgPrevPtr_offset", + "openocd_OS_TCB_DbgNextPtr_offset", + NULL +}; + +enum uCOS_III_symbol_values { + uCOS_III_VAL_OSRunning, + uCOS_III_VAL_OSTCBCurPtr, + uCOS_III_VAL_OSTaskDbgListPtr, + uCOS_III_VAL_OSTaskQty, + + /* also see: contrib/rtos-helpers/uCOS-III-openocd.c */ + uCOS_III_VAL_OS_TCB_StkPtr_offset, + uCOS_III_VAL_OS_TCB_NamePtr_offset, + uCOS_III_VAL_OS_TCB_TaskState_offset, + uCOS_III_VAL_OS_TCB_Prio_offset, + uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset, + uCOS_III_VAL_OS_TCB_DbgNextPtr_offset, +}; + +static const char * const uCOS_III_thread_state_list[] = { + "Ready", + "Delay", + "Pend", + "Pend Timeout", + "Suspended", + "Delay Suspended", + "Pend Suspended", + "Pend Timeout Suspended", +}; + +static int uCOS_III_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address, + threadid_t *threadid) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + size_t thread_index; + + for (thread_index = 0; thread_index < params->num_threads; thread_index++) + if (params->threads[thread_index] == thread_address) + goto found; + + if (params->num_threads == UCOS_III_MAX_THREADS) { + LOG_WARNING("uCOS-III: too many threads; increase UCOS_III_MAX_THREADS"); + return ERROR_FAIL; + } + + params->threads[thread_index] = thread_address; + params->num_threads++; +found: + *threadid = thread_index + params->threadid_start; + return ERROR_OK; +} + +static int uCOS_III_find_thread_address(struct rtos *rtos, threadid_t threadid, + symbol_address_t *thread_address) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + size_t thread_index; + + thread_index = threadid - params->threadid_start; + if (thread_index >= params->num_threads) { + LOG_ERROR("uCOS-III: failed to find thread address"); + return ERROR_FAIL; + } + + *thread_address = params->threads[thread_index]; + return ERROR_OK; +} + +static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + int retval; + + /* read the thread list head */ + symbol_address_t thread_list_address = 0; + + retval = target_read_memory(rtos->target, + rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address, + params->pointer_width, + 1, + (void *)&thread_list_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread list address"); + return retval; + } + + /* advance to end of thread list */ + do { + *thread_address = thread_list_address; + + retval = target_read_memory(rtos->target, + thread_list_address + params->thread_next_offset, + params->pointer_width, + 1, + (void *)&thread_list_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read next thread address"); + return retval; + } + } while (thread_list_address != 0); + + return ERROR_OK; +} + +static int uCOS_III_update_thread_offsets(struct rtos *rtos) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + + if (params->thread_offsets_updated) + return ERROR_OK; + + const struct thread_offset_map { + enum uCOS_III_symbol_values symbol_value; + symbol_address_t *thread_offset; + } thread_offset_maps[] = { + { + uCOS_III_VAL_OS_TCB_StkPtr_offset, + ¶ms->thread_stack_offset, + }, + { + uCOS_III_VAL_OS_TCB_NamePtr_offset, + ¶ms->thread_name_offset, + }, + { + uCOS_III_VAL_OS_TCB_TaskState_offset, + ¶ms->thread_state_offset, + }, + { + uCOS_III_VAL_OS_TCB_Prio_offset, + ¶ms->thread_priority_offset, + }, + { + uCOS_III_VAL_OS_TCB_DbgPrevPtr_offset, + ¶ms->thread_prev_offset, + }, + { + uCOS_III_VAL_OS_TCB_DbgNextPtr_offset, + ¶ms->thread_next_offset, + }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(thread_offset_maps); i++) { + const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i]; + + int retval = target_read_memory(rtos->target, + rtos->symbols[thread_offset_map->symbol_value].address, + params->pointer_width, + 1, + (void *)thread_offset_map->thread_offset); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread offset"); + return retval; + } + } + + params->thread_offsets_updated = true; + return ERROR_OK; +} + +static int uCOS_III_detect_rtos(struct target *target) +{ + return target->rtos->symbols != NULL && + target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; +} + +static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) +{ + struct uCOS_III_params *params = target->rtos->rtos_specific_params; + + params->thread_offsets_updated = false; + params->num_threads = 0; + + return ERROR_OK; +} + +static int uCOS_III_create(struct target *target) +{ + struct uCOS_III_params *params; + + for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++) + if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) { + params = malloc(sizeof(*params) + + UCOS_III_MAX_THREADS * sizeof(*params->threads)); + if (params == NULL) { + LOG_ERROR("uCOS-III: out of memory"); + return ERROR_FAIL; + } + + memcpy(params, &uCOS_III_params_list[i], sizeof(uCOS_III_params_list[i])); + target->rtos->rtos_specific_params = (void *)params; + + target_register_reset_callback(uCOS_III_reset_handler, NULL); + + return ERROR_OK; + } + + LOG_ERROR("uCOS-III: target not supported: %s", target->type->name); + return ERROR_FAIL; +} + +static int uCOS_III_update_threads(struct rtos *rtos) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + int retval; + + /* free previous thread details */ + rtos_free_threadlist(rtos); + + /* verify RTOS is running */ + uint8_t rtos_running; + + retval = target_read_u8(rtos->target, + rtos->symbols[uCOS_III_VAL_OSRunning].address, + &rtos_running); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read RTOS running"); + return retval; + } + + if (!rtos_running) { + rtos->thread_details = calloc(1, sizeof(struct thread_detail)); + if (rtos->thread_details == NULL) { + LOG_ERROR("uCOS-III: out of memory"); + return ERROR_FAIL; + } + + rtos->thread_count = 1; + rtos->thread_details->threadid = 0; + rtos->thread_details->exists = true; + rtos->current_thread = 0; + + return ERROR_OK; + } + + /* update thread offsets */ + retval = uCOS_III_update_thread_offsets(rtos); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to update thread offsets"); + return retval; + } + + /* read current thread address */ + symbol_address_t current_thread_address = 0; + + retval = target_read_memory(rtos->target, + rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, + params->pointer_width, + 1, + (void *)¤t_thread_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read current thread address"); + return retval; + } + + /* read number of tasks */ + retval = target_read_u16(rtos->target, + rtos->symbols[uCOS_III_VAL_OSTaskQty].address, + (void *)&rtos->thread_count); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread count"); + return retval; + } + + rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail)); + if (rtos->thread_details == NULL) { + LOG_ERROR("uCOS-III: out of memory"); + return ERROR_FAIL; + } + + /* + * uC/OS-III adds tasks in LIFO order; advance to the end of the + * list and work backwards to preserve the intended order. + */ + symbol_address_t thread_address = 0; + + retval = uCOS_III_find_last_thread_address(rtos, &thread_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to find last thread address"); + return retval; + } + + for (int i = 0; i < rtos->thread_count; i++) { + struct thread_detail *thread_detail = &rtos->thread_details[i]; + char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; + + /* find or create new threadid */ + retval = uCOS_III_find_or_create_thread(rtos, + thread_address, + &thread_detail->threadid); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to find or create thread"); + return retval; + } + + if (thread_address == current_thread_address) + rtos->current_thread = thread_detail->threadid; + + thread_detail->exists = true; + + /* read thread name */ + symbol_address_t thread_name_address = 0; + + retval = target_read_memory(rtos->target, + thread_address + params->thread_name_offset, + params->pointer_width, + 1, + (void *)&thread_name_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to name address"); + return retval; + } + + retval = target_read_buffer(rtos->target, + thread_name_address, + sizeof(thread_str_buffer), + (void *)thread_str_buffer); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread name"); + return retval; + } + + thread_str_buffer[sizeof(thread_str_buffer) - 1] = '\0'; + thread_detail->thread_name_str = strdup(thread_str_buffer); + + /* read thread extra info */ + uint8_t thread_state; + uint8_t thread_priority; + + retval = target_read_u8(rtos->target, + thread_address + params->thread_state_offset, + &thread_state); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread state"); + return retval; + } + + retval = target_read_u8(rtos->target, + thread_address + params->thread_priority_offset, + &thread_priority); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read thread priority"); + return retval; + } + + const char *thread_state_str; + + if (thread_state < ARRAY_SIZE(uCOS_III_thread_state_list)) + thread_state_str = uCOS_III_thread_state_list[thread_state]; + else + thread_state_str = "Unknown"; + + snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d", + thread_state_str, thread_priority); + thread_detail->extra_info_str = strdup(thread_str_buffer); + + /* read previous thread address */ + retval = target_read_memory(rtos->target, + thread_address + params->thread_prev_offset, + params->pointer_width, + 1, + (void *)&thread_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read previous thread address"); + return retval; + } + } + + return ERROR_OK; +} + +static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, char **hex_reg_list) +{ + struct uCOS_III_params *params = rtos->rtos_specific_params; + int retval; + + /* find thread address for threadid */ + symbol_address_t thread_address = 0; + + retval = uCOS_III_find_thread_address(rtos, threadid, &thread_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to find thread address"); + return retval; + } + + /* read thread stack address */ + symbol_address_t stack_address = 0; + + retval = target_read_memory(rtos->target, + thread_address + params->thread_stack_offset, + params->pointer_width, + 1, + (void *)&stack_address); + if (retval != ERROR_OK) { + LOG_ERROR("uCOS-III: failed to read stack address"); + return retval; + } + + return rtos_generic_stack_read(rtos->target, + params->stacking_info, + stack_address, + hex_reg_list); +} + +static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t)); + if (*symbol_list == NULL) { + LOG_ERROR("uCOS-III: out of memory"); + return ERROR_FAIL; + } + + for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_symbol_list); i++) + (*symbol_list)[i].symbol_name = uCOS_III_symbol_list[i]; + + return ERROR_OK; +} + +const struct rtos_type uCOS_III_rtos = { + .name = "uCOS-III", + .detect_rtos = uCOS_III_detect_rtos, + .create = uCOS_III_create, + .update_threads = uCOS_III_update_threads, + .get_thread_reg_list = uCOS_III_get_thread_reg_list, + .get_symbol_list_to_lookup = uCOS_III_get_symbol_list_to_lookup, +}; |