diff options
author | Daniel Krebs <github@daniel-krebs.net> | 2015-10-05 15:37:57 +0200 |
---|---|---|
committer | Antonio Borneo <borneo.antonio@gmail.com> | 2020-07-26 20:11:52 +0100 |
commit | 6a78c8581d81665969f24563faccd220de517961 (patch) | |
tree | eef19f0bcb6ec91bae848dd9b060bc50f5e5ed2d /src/rtos/riot.c | |
parent | cf902f7034efd8c9db248b631420838679e9a1ed (diff) | |
download | riscv-openocd-6a78c8581d81665969f24563faccd220de517961.zip riscv-openocd-6a78c8581d81665969f24563faccd220de517961.tar.gz riscv-openocd-6a78c8581d81665969f24563faccd220de517961.tar.bz2 |
rtos: add support for RIOT
Add threads support for RIOT (https://github.com/RIOT-OS/RIOT).
Original code is from Daniel Krebs.
Change-Id: I83fe3b91dd75949e800b5aea1015d8fa37b09c61
Signed-off-by: Daniel Krebs <github@daniel-krebs.net>
Signed-off-by: Vincent Dupont <vincent@otakeys.com>
Signed-off-by: Benjamin Valentin <benpicco@googlemail.com>
Reviewed-on: http://openocd.zylin.com/4256
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Diffstat (limited to 'src/rtos/riot.c')
-rw-r--r-- | src/rtos/riot.c | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/src/rtos/riot.c b/src/rtos/riot.c new file mode 100644 index 0000000..15cbb0f --- /dev/null +++ b/src/rtos/riot.c @@ -0,0 +1,428 @@ +/*************************************************************************** + * Copyright (C) 2015 by Daniel Krebs * + * Daniel Krebs - github@daniel-krebs.net * + * * + * 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 "target/armv7m.h" +#include "rtos_riot_stackings.h" + +static bool riot_detect_rtos(struct target *target); +static int riot_create(struct target *target); +static int riot_update_threads(struct rtos *rtos); +static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs); +static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); + +struct riot_thread_state { + int value; + const char *desc; +}; + +/* refer RIOT sched.h */ +static const struct riot_thread_state riot_thread_states[] = { + { 0, "Stopped" }, + { 1, "Zombie" }, + { 2, "Sleeping" }, + { 3, "Blocked mutex" }, + { 4, "Blocked receive" }, + { 5, "Blocked send" }, + { 6, "Blocked reply" }, + { 7, "Blocked any flag" }, + { 8, "Blocked all flags" }, + { 9, "Blocked mbox" }, + { 10, "Blocked condition" }, + { 11, "Running" }, + { 12, "Pending" }, +}; +#define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states) + +struct riot_params { + const char *target_name; + unsigned char thread_sp_offset; + unsigned char thread_status_offset; +}; + +static const struct riot_params riot_params_list[] = { + { + "cortex_m", /* target_name */ + 0x00, /* thread_sp_offset */ + 0x04, /* thread_status_offset */ + }, + { /* STLink */ + "hla_target", /* target_name */ + 0x00, /* thread_sp_offset */ + 0x04, /* thread_status_offset */ + } +}; +#define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list) + +/* Initialize in riot_create() depending on architecture */ +static const struct rtos_register_stacking *stacking_info; + +enum riot_symbol_values { + RIOT_THREADS_BASE = 0, + RIOT_NUM_THREADS, + RIOT_ACTIVE_PID, + RIOT_MAX_THREADS, + RIOT_NAME_OFFSET, +}; + +/* refer RIOT core/sched.c */ +static const char *const riot_symbol_list[] = { + "sched_threads", + "sched_num_threads", + "sched_active_pid", + "max_threads", + "_tcb_name_offset", + NULL +}; + +/* Define which symbols are not mandatory */ +static const enum riot_symbol_values riot_optional_symbols[] = { + RIOT_NAME_OFFSET, +}; + +const struct rtos_type riot_rtos = { + .name = "RIOT", + .detect_rtos = riot_detect_rtos, + .create = riot_create, + .update_threads = riot_update_threads, + .get_thread_reg_list = riot_get_thread_reg_list, + .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup, +}; + +static int riot_update_threads(struct rtos *rtos) +{ + int retval; + unsigned int tasks_found = 0; + const struct riot_params *param; + + if (rtos == NULL) + return ERROR_FAIL; + + if (rtos->rtos_specific_params == NULL) + return ERROR_FAIL; + + param = (const struct riot_params *)rtos->rtos_specific_params; + + if (rtos->symbols == NULL) { + LOG_ERROR("No symbols for RIOT"); + return ERROR_FAIL; + } + + if (rtos->symbols[RIOT_THREADS_BASE].address == 0) { + LOG_ERROR("Can't find symbol `%s`", + riot_symbol_list[RIOT_THREADS_BASE]); + return ERROR_FAIL; + } + + /* wipe out previous thread details if any */ + rtos_free_threadlist(rtos); + + /* Reset values */ + rtos->current_thread = 0; + rtos->thread_count = 0; + + /* read the current thread id */ + int16_t active_pid = 0; + retval = target_read_u16(rtos->target, + rtos->symbols[RIOT_ACTIVE_PID].address, + (uint16_t *)&active_pid); + if (retval != ERROR_OK) { + LOG_ERROR("Can't read symbol `%s`", + riot_symbol_list[RIOT_ACTIVE_PID]); + return retval; + } + rtos->current_thread = active_pid; + + /* read the current thread count + * It's `int` in RIOT, but this is Cortex M* only anyway */ + int32_t thread_count = 0; + retval = target_read_u16(rtos->target, + rtos->symbols[RIOT_NUM_THREADS].address, + (uint16_t *)&thread_count); + if (retval != ERROR_OK) { + LOG_ERROR("Can't read symbol `%s`", + riot_symbol_list[RIOT_NUM_THREADS]); + return retval; + } + rtos->thread_count = thread_count; + + /* read the maximum number of threads */ + uint8_t max_threads = 0; + retval = target_read_u8(rtos->target, + rtos->symbols[RIOT_MAX_THREADS].address, + &max_threads); + if (retval != ERROR_OK) { + LOG_ERROR("Can't read symbol `%s`", + riot_symbol_list[RIOT_MAX_THREADS]); + return retval; + } + + /* Base address of thread array */ + uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address; + + /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled + * with DEVELHELP, so there are no thread names */ + uint8_t name_offset = 0; + if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) { + retval = target_read_u8(rtos->target, + rtos->symbols[RIOT_NAME_OFFSET].address, + &name_offset); + if (retval != ERROR_OK) { + LOG_ERROR("Can't read symbol `%s`", + riot_symbol_list[RIOT_NAME_OFFSET]); + return retval; + } + } + + /* Allocate memory for thread description */ + rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail)); + if (rtos->thread_details == NULL) { + LOG_ERROR("RIOT: out of memory"); + return ERROR_FAIL; + } + + /* Buffer for thread names, maximum to display is 32 */ + char buffer[32]; + + for (unsigned int i = 0; i < max_threads; i++) { + /* get pointer to tcb_t */ + uint32_t tcb_pointer = 0; + retval = target_read_u32(rtos->target, + threads_base + (i * 4), + &tcb_pointer); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + goto error; + } + + if (tcb_pointer == 0) { + /* PID unused */ + continue; + } + + /* Index is PID */ + rtos->thread_details[tasks_found].threadid = i; + + /* read thread state */ + uint8_t status = 0; + retval = target_read_u8(rtos->target, + tcb_pointer + param->thread_status_offset, + &status); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + goto error; + } + + /* Search for state */ + unsigned int k; + for (k = 0; k < RIOT_NUM_STATES; k++) { + if (riot_thread_states[k].value == status) + break; + } + + /* Copy state string */ + if (k >= RIOT_NUM_STATES) { + rtos->thread_details[tasks_found].extra_info_str = + strdup("unknown state"); + } else { + rtos->thread_details[tasks_found].extra_info_str = + strdup(riot_thread_states[k].desc); + } + + if (rtos->thread_details[tasks_found].extra_info_str == NULL) { + LOG_ERROR("RIOT: out of memory"); + retval = ERROR_FAIL; + goto error; + } + + /* Thread names are only available if compiled with DEVELHELP */ + if (name_offset != 0) { + uint32_t name_pointer = 0; + retval = target_read_u32(rtos->target, + tcb_pointer + name_offset, + &name_pointer); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", + riot_symbol_list[RIOT_THREADS_BASE]); + goto error; + } + + /* read thread name */ + retval = target_read_buffer(rtos->target, + name_pointer, + sizeof(buffer), + (uint8_t *)&buffer); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", + riot_symbol_list[RIOT_THREADS_BASE]); + goto error; + } + + /* Make sure the string in the buffer terminates */ + if (buffer[sizeof(buffer) - 1] != 0) + buffer[sizeof(buffer) - 1] = 0; + + /* Copy thread name */ + rtos->thread_details[tasks_found].thread_name_str = + strdup(buffer); + + } else { + rtos->thread_details[tasks_found].thread_name_str = + strdup("Enable DEVELHELP to see task names"); + } + + if (rtos->thread_details[tasks_found].thread_name_str == NULL) { + LOG_ERROR("RIOT: out of memory"); + retval = ERROR_FAIL; + goto error; + } + + rtos->thread_details[tasks_found].exists = true; + + tasks_found++; + } + + return ERROR_OK; + +error: + rtos_free_threadlist(rtos); + return retval; +} + +static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, + struct rtos_reg **reg_list, int *num_regs) +{ + int retval; + const struct riot_params *param; + + if (rtos == NULL) + return ERROR_FAIL; + + if (thread_id == 0) + return ERROR_FAIL; + + if (rtos->rtos_specific_params == NULL) + return ERROR_FAIL; + + param = (const struct riot_params *)rtos->rtos_specific_params; + + /* find the thread with given thread id */ + uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address; + uint32_t tcb_pointer = 0; + retval = target_read_u32(rtos->target, + threads_base + (thread_id * 4), + &tcb_pointer); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + return retval; + } + + /* read stack pointer for that thread */ + uint32_t stackptr = 0; + retval = target_read_u32(rtos->target, + tcb_pointer + param->thread_sp_offset, + &stackptr); + if (retval != ERROR_OK) { + LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]); + return retval; + } + + return rtos_generic_stack_read(rtos->target, + stacking_info, + stackptr, + reg_list, + num_regs); +} + +static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +{ + *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(symbol_table_elem_t)); + + if (*symbol_list == NULL) { + LOG_ERROR("RIOT: out of memory"); + return ERROR_FAIL; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) { + (*symbol_list)[i].symbol_name = riot_symbol_list[i]; + (*symbol_list)[i].optional = false; + + /* Lookup if symbol is optional */ + for (unsigned int k = 0; k < sizeof(riot_optional_symbols); k++) { + if (i == riot_optional_symbols[k]) { + (*symbol_list)[i].optional = true; + break; + } + } + } + + return ERROR_OK; +} + +static bool riot_detect_rtos(struct target *target) +{ + if ((target->rtos->symbols != NULL) && + (target->rtos->symbols[RIOT_THREADS_BASE].address != 0)) { + /* looks like RIOT */ + return true; + } + return false; +} + +static int riot_create(struct target *target) +{ + unsigned int i = 0; + + /* lookup if target is supported by RIOT */ + while ((i < RIOT_NUM_PARAMS) && + (0 != strcmp(riot_params_list[i].target_name, target->type->name))) { + i++; + } + if (i >= RIOT_NUM_PARAMS) { + LOG_ERROR("Could not find target in RIOT compatibility list"); + return ERROR_FAIL; + } + + target->rtos->rtos_specific_params = (void *)&riot_params_list[i]; + target->rtos->current_thread = 0; + target->rtos->thread_details = NULL; + + /* Stacking is different depending on architecture */ + struct armv7m_common *armv7m_target = target_to_armv7m(target); + + if (armv7m_target->arm.is_armv6m) + stacking_info = &rtos_riot_cortex_m0_stacking; + else if (is_armv7m(armv7m_target)) + stacking_info = &rtos_riot_cortex_m34_stacking; + else { + LOG_ERROR("No stacking info for architecture"); + return ERROR_FAIL; + } + return ERROR_OK; +} |