From: Moritz Fischer Date: Sun, 30 Sep 2018 00:50:06 +0000 (-0700) Subject: rtos: Add RTOS task awareness for Chromium-EC X-Git-Tag: v0.11.0-rc1~867 X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=731dc36a678ba44a40da30d5bd614d5df85b271d;hp=d2fb461621dc97a611e7bb44a2a64e1efe300875 rtos: Add RTOS task awareness for Chromium-EC Add RTOS task awareness for Chromium-EC. Currently only supports ARM Cortex-M0/M3/M4 based targets. No new Clang Analyzer warnings. Change-Id: Iea56fcb1be220e2437613922879b63d6e553703d Signed-off-by: Moritz Fischer Reviewed-on: http://openocd.zylin.com/4685 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Matthias Welwarsky --- diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am index c8c4023032..bbf66a6349 100644 --- a/src/rtos/Makefile.am +++ b/src/rtos/Makefile.am @@ -12,6 +12,7 @@ noinst_LTLIBRARIES += %D%/librtos.la %D%/eCos.c \ %D%/linux.c \ %D%/ChibiOS.c \ + %D%/chromium-ec.c \ %D%/embKernel.c \ %D%/mqx.c \ %D%/uCOS-III.c \ diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c new file mode 100644 index 0000000000..92ed2cbadc --- /dev/null +++ b/src/rtos/chromium-ec.c @@ -0,0 +1,387 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2018 National Instruments Corp + * Author: Moritz Fischer + * + * Chromium-EC RTOS Task Awareness + */ + +#include +#include +#include + +#include "rtos_standard_stackings.h" + +#define CROS_EC_MAX_TASKS 32 +#define CROS_EC_MAX_NAME 200 +#define CROS_EC_IDLE_STRING "<< idle >>" +#define BIT(x) (1 << (x)) + +struct chromium_ec_params { + const char *target_name; + size_t ptr_size; + off_t task_offset_next; + off_t task_offset_sp; + off_t task_offset_events; + off_t task_offset_runtime; + const struct rtos_register_stacking *stacking; +}; + +static const struct chromium_ec_params chromium_ec_params_list[] = { + { + .target_name = "hla_target", + .ptr_size = 4, + .task_offset_next = 24, + .task_offset_sp = 0, + .task_offset_events = 4, + .task_offset_runtime = 8, + .stacking = &rtos_standard_Cortex_M3_stacking, + + }, + { + .target_name = "cortex_m", + .ptr_size = 4, + .task_offset_next = 24, + .task_offset_sp = 0, + .task_offset_events = 4, + .task_offset_runtime = 8, + .stacking = &rtos_standard_Cortex_M3_stacking, + }, +}; + +static const char * const chromium_ec_symbol_list[] = { + "start_called", + "current_task", + "tasks", + "tasks_enabled", + "tasks_ready", + "task_names", + "build_info", + NULL, +}; + +enum chromium_ec_symbol_values { + CHROMIUM_EC_VAL_start_called = 0, + CHROMIUM_EC_VAL_current_task, + CHROMIUM_EC_VAL_tasks, + CHROMIUM_EC_VAL_tasks_enabled, + CHROMIUM_EC_VAL_tasks_ready, + CHROMIUM_EC_VAL_task_names, + CHROMIUM_EC_VAL_build_info, + + CHROMIUM_EC_VAL_COUNT, +}; + +#define CROS_EC_MAX_BUILDINFO 512 + +static bool chromium_ec_detect_rtos(struct target *target) +{ + char build_info_buf[CROS_EC_MAX_BUILDINFO]; + enum chromium_ec_symbol_values sym; + int ret; + + if (!target || !target->rtos || !target->rtos->symbols) + return false; + + for (sym = CHROMIUM_EC_VAL_start_called; + sym < CHROMIUM_EC_VAL_COUNT; sym++) { + if (target->rtos->symbols[sym].address) { + LOG_DEBUG("Chromium-EC: Symbol \"%s\" found", + chromium_ec_symbol_list[sym]); + } else { + LOG_ERROR("Chromium-EC: Symbol \"%s\" missing", + chromium_ec_symbol_list[sym]); + return false; + } + } + + ret = target_read_buffer(target, + target->rtos->symbols[CHROMIUM_EC_VAL_build_info].address, + sizeof(build_info_buf), + (uint8_t *)build_info_buf); + + if (ret != ERROR_OK) + return false; + + LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf); + + return target->rtos->symbols && + target->rtos->symbols[CHROMIUM_EC_VAL_start_called].address; +} + +static int chromium_ec_create(struct target *target) +{ + struct chromium_ec_params *params; + size_t t; + + for (t = 0; t < ARRAY_SIZE(chromium_ec_params_list); t++) + if (!strcmp(chromium_ec_params_list[t].target_name, target->type->name)) { + params = malloc(sizeof(*params)); + if (!params) { + LOG_ERROR("Chromium-EC: out of memory"); + return ERROR_FAIL; + } + + memcpy(params, &chromium_ec_params_list[t], sizeof(*params)); + target->rtos->rtos_specific_params = (void *)params; + target->rtos->current_thread = 0; + target->rtos->thread_details = NULL; + target->rtos->thread_count = 0; + + LOG_INFO("Chromium-EC: Using target: %s", target->type->name); + return ERROR_OK; + } + + LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name); + return ERROR_FAIL; +} + +static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task) +{ + if (!rtos || !rtos->symbols) + return ERROR_FAIL; + + return target_read_u32(rtos->target, + rtos->symbols[CHROMIUM_EC_VAL_current_task].address, + current_task); +} + +static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks) +{ + uint32_t tasks_enabled; + int ret, t, found; + + ret = target_read_u32(rtos->target, + rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address, + &tasks_enabled); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to determine #of tasks"); + return ret; + } + + found = 0; + for (t = 0; t < CROS_EC_MAX_TASKS; t++) + if (tasks_enabled & BIT(t)) + found++; + + *num_tasks = found; + + return ERROR_OK; +} + +static int chromium_ec_update_threads(struct rtos *rtos) +{ + uint32_t tasks_enabled, tasks_ready, start_called; + uint32_t current_task, thread_ptr, name_ptr; + char thread_str_buf[CROS_EC_MAX_NAME]; + int ret, t, num_tasks, tasks_found; + struct chromium_ec_params *params; + uint8_t runtime_buf[8]; + uint64_t runtime; + uint32_t events; + + params = rtos->rtos_specific_params; + if (!params) + return ERROR_FAIL; + + if (!rtos->symbols) + return ERROR_FAIL; + + num_tasks = 0; + ret = chromium_ec_get_num_tasks(rtos, &num_tasks); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to get number of tasks"); + return ret; + } + + current_task = 0; + ret = chromium_ec_get_current_task_ptr(rtos, ¤t_task); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to get current task"); + return ret; + } + LOG_DEBUG("Current task: %lx tasks_found: %d", + (unsigned long)current_task, + num_tasks); + + /* set current task to what we read */ + rtos->current_thread = current_task; + + /* Nuke the old tasks */ + rtos_free_threadlist(rtos); + + /* One check if task switching has started ... */ + start_called = 0; + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_start_called].address, + &start_called); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to load start_called"); + return ret; + } + + if (!rtos->current_thread || !num_tasks || !start_called) { + num_tasks++; + + rtos->thread_details = malloc( + sizeof(struct thread_detail) * num_tasks); + rtos->thread_details->threadid = 1; + rtos->thread_details->exists = true; + rtos->thread_details->extra_info_str = NULL; + rtos->thread_details->thread_name_str = strdup("Current Execution"); + + if (!num_tasks || !start_called) { + rtos->thread_count = 1; + return ERROR_OK; + } + } else { + /* create space for new thread details */ + rtos->thread_details = malloc( + sizeof(struct thread_detail) * num_tasks); + } + + tasks_enabled = 0; + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address, + &tasks_enabled); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to load tasks_enabled"); + return ret; + } + + tasks_ready = 0; + ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_ready].address, + &tasks_ready); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to load tasks_ready"); + return ret; + } + + thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_tasks].address; + + tasks_found = 0; + for (t = 0; t < CROS_EC_MAX_TASKS; t++) { + if (!(tasks_enabled & BIT(t))) + continue; + + if (thread_ptr == current_task) + rtos->current_thread = thread_ptr; + + rtos->thread_details[tasks_found].threadid = thread_ptr; + ret = target_read_u32(rtos->target, + rtos->symbols[CHROMIUM_EC_VAL_task_names].address + + params->ptr_size * t, &name_ptr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read name_ptr"); + return ret; + } + + /* read name buffer */ + ret = target_read_buffer(rtos->target, name_ptr, CROS_EC_MAX_NAME, + (uint8_t *)thread_str_buf); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read task name"); + return ret; + } + + /* sanitize string, gdb chokes on "<< idle >>" */ + if (thread_str_buf[CROS_EC_MAX_NAME - 1] != '\0') + thread_str_buf[CROS_EC_MAX_NAME - 1] = '\0'; + if (!strncmp(thread_str_buf, CROS_EC_IDLE_STRING, CROS_EC_MAX_NAME)) + rtos->thread_details[tasks_found].thread_name_str = strdup("IDLE"); + else + rtos->thread_details[tasks_found].thread_name_str = strdup(thread_str_buf); + + events = 0; + ret = target_read_u32(rtos->target, + thread_ptr + params->task_offset_events, + &events); + if (ret != ERROR_OK) + LOG_ERROR("Failed to get task %d's events", t); + + /* this is a bit kludgy but will do for now */ + ret = target_read_buffer(rtos->target, + thread_ptr + params->task_offset_runtime, + sizeof(runtime_buf), runtime_buf); + if (ret != ERROR_OK) + LOG_ERROR("Failed to get task %d's runtime", t); + runtime = target_buffer_get_u64(rtos->target, runtime_buf); + + /* Priority is simply the positon in the array */ + if (thread_ptr == current_task) + snprintf(thread_str_buf, sizeof(thread_str_buf), + "State: Running, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n", + t, events, runtime); + else + snprintf(thread_str_buf, sizeof(thread_str_buf), + "State: %s, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n", + tasks_ready & BIT(t) ? "Ready" : "Waiting", t, + events, runtime); + + rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf); + rtos->thread_details[tasks_found].exists = true; + + thread_ptr += params->task_offset_next; + + tasks_found++; + } + + rtos->thread_count = tasks_found; + + return ERROR_OK; +} + +static int chromium_ec_get_thread_reg_list(struct rtos *rtos, + threadid_t threadid, + struct rtos_reg **reg_list, + int *num_regs) +{ + struct chromium_ec_params *params = rtos->rtos_specific_params; + uint32_t stack_ptr = 0; + int ret, t; + + for (t = 0; t < rtos->thread_count; t++) + if (threadid == rtos->thread_details[t].threadid) + break; + + /* if we didn't find threadid, bail */ + if (t == rtos->thread_count) + return ERROR_FAIL; + + ret = target_read_u32(rtos->target, + rtos->symbols[CHROMIUM_EC_VAL_tasks].address + + params->task_offset_next * t, + &stack_ptr); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to load TCB"); + return ret; + } + + return rtos_generic_stack_read(rtos->target, params->stacking, + stack_ptr, reg_list, num_regs); +} + +static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) +{ + size_t s; + + *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list), + sizeof(symbol_table_elem_t)); + if (!(*symbol_list)) { + LOG_ERROR("Chromium-EC: out of memory"); + return ERROR_FAIL; + } + + for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++) + (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s]; + + return ERROR_OK; +} + +const struct rtos_type chromium_ec_rtos = { + .name = "Chromium-EC", + .detect_rtos = chromium_ec_detect_rtos, + .create = chromium_ec_create, + .update_threads = chromium_ec_update_threads, + .get_thread_reg_list = chromium_ec_get_thread_reg_list, + .get_symbol_list_to_lookup = chromium_ec_get_symbol_list_to_lookup, +}; diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 8ca1183b02..cd2e271f68 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -32,6 +32,7 @@ extern struct rtos_type ThreadX_rtos; extern struct rtos_type eCos_rtos; extern struct rtos_type Linux_os; extern struct rtos_type ChibiOS_rtos; +extern struct rtos_type chromium_ec_rtos; extern struct rtos_type embKernel_rtos; extern struct rtos_type mqx_rtos; extern struct rtos_type uCOS_III_rtos; @@ -43,6 +44,7 @@ static struct rtos_type *rtos_types[] = { &eCos_rtos, &Linux_os, &ChibiOS_rtos, + &chromium_ec_rtos, &embKernel_rtos, &mqx_rtos, &uCOS_III_rtos,