aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rtos/Makefile.am1
-rw-r--r--src/rtos/chromium-ec.c387
-rw-r--r--src/rtos/rtos.c2
3 files changed, 390 insertions, 0 deletions
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index c8c4023..bbf66a6 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 0000000..92ed2cb
--- /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 <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,
+};
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 8ca1183..cd2e271 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,