rtos: Add RTOS task awareness for Chromium-EC
authorMoritz Fischer <moritz.fischer@ettus.com>
Sun, 30 Sep 2018 00:50:06 +0000 (17:50 -0700)
committerMatthias Welwarsky <matthias@welwarsky.de>
Wed, 23 Jan 2019 15:27:01 +0000 (15:27 +0000)
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 <moritz.fischer@ettus.com>
Reviewed-on: http://openocd.zylin.com/4685
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
src/rtos/Makefile.am
src/rtos/chromium-ec.c [new file with mode: 0644]
src/rtos/rtos.c

index c8c402303291224949b4fc895531b7c938fe66a8..bbf66a63497671fdc98b6801b01e15d45db33ca5 100644 (file)
@@ -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 (file)
index 0000000..92ed2cb
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2018 National Instruments Corp
+ * Author: Moritz Fischer <moritz.fischer@ettus.com>
+ *
+ * Chromium-EC RTOS Task Awareness
+ */
+
+#include <rtos/rtos.h>
+#include <target/target.h>
+#include <target/target_type.h>
+
+#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, &current_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,
+};
index 8ca1183b0234e8c1595cf3b7eaef7fc7079d25d6..cd2e271f68beea23b37c445f29a1beede3e53a64 100644 (file)
@@ -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,