rtos: Add RTOS task awareness for Chromium-EC 85/4685/10
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,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)