openocd/src/rtos/chromium-ec.c

392 lines
10 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018 National Instruments Corp
* Author: Moritz Fischer <moritz.fischer@ettus.com>
*
* Chromium-EC RTOS Task Awareness
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/bits.h>
#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 >>"
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 position 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(struct symbol_table_elem *symbol_list[])
{
size_t s;
*symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
sizeof(struct symbol_table_elem));
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,
};