Fix 'adapter usb location' documentation
[openocd.git] / src / rtos / chromium-ec.c
blob92ed2cbadcda6c51937b18b059603f2c67f1a5cf
1 /*
2 * SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2018 National Instruments Corp
5 * Author: Moritz Fischer <moritz.fischer@ettus.com>
7 * Chromium-EC RTOS Task Awareness
8 */
10 #include <rtos/rtos.h>
11 #include <target/target.h>
12 #include <target/target_type.h>
14 #include "rtos_standard_stackings.h"
16 #define CROS_EC_MAX_TASKS 32
17 #define CROS_EC_MAX_NAME 200
18 #define CROS_EC_IDLE_STRING "<< idle >>"
19 #define BIT(x) (1 << (x))
21 struct chromium_ec_params {
22 const char *target_name;
23 size_t ptr_size;
24 off_t task_offset_next;
25 off_t task_offset_sp;
26 off_t task_offset_events;
27 off_t task_offset_runtime;
28 const struct rtos_register_stacking *stacking;
31 static const struct chromium_ec_params chromium_ec_params_list[] = {
33 .target_name = "hla_target",
34 .ptr_size = 4,
35 .task_offset_next = 24,
36 .task_offset_sp = 0,
37 .task_offset_events = 4,
38 .task_offset_runtime = 8,
39 .stacking = &rtos_standard_Cortex_M3_stacking,
43 .target_name = "cortex_m",
44 .ptr_size = 4,
45 .task_offset_next = 24,
46 .task_offset_sp = 0,
47 .task_offset_events = 4,
48 .task_offset_runtime = 8,
49 .stacking = &rtos_standard_Cortex_M3_stacking,
53 static const char * const chromium_ec_symbol_list[] = {
54 "start_called",
55 "current_task",
56 "tasks",
57 "tasks_enabled",
58 "tasks_ready",
59 "task_names",
60 "build_info",
61 NULL,
64 enum chromium_ec_symbol_values {
65 CHROMIUM_EC_VAL_start_called = 0,
66 CHROMIUM_EC_VAL_current_task,
67 CHROMIUM_EC_VAL_tasks,
68 CHROMIUM_EC_VAL_tasks_enabled,
69 CHROMIUM_EC_VAL_tasks_ready,
70 CHROMIUM_EC_VAL_task_names,
71 CHROMIUM_EC_VAL_build_info,
73 CHROMIUM_EC_VAL_COUNT,
76 #define CROS_EC_MAX_BUILDINFO 512
78 static bool chromium_ec_detect_rtos(struct target *target)
80 char build_info_buf[CROS_EC_MAX_BUILDINFO];
81 enum chromium_ec_symbol_values sym;
82 int ret;
84 if (!target || !target->rtos || !target->rtos->symbols)
85 return false;
87 for (sym = CHROMIUM_EC_VAL_start_called;
88 sym < CHROMIUM_EC_VAL_COUNT; sym++) {
89 if (target->rtos->symbols[sym].address) {
90 LOG_DEBUG("Chromium-EC: Symbol \"%s\" found",
91 chromium_ec_symbol_list[sym]);
92 } else {
93 LOG_ERROR("Chromium-EC: Symbol \"%s\" missing",
94 chromium_ec_symbol_list[sym]);
95 return false;
99 ret = target_read_buffer(target,
100 target->rtos->symbols[CHROMIUM_EC_VAL_build_info].address,
101 sizeof(build_info_buf),
102 (uint8_t *)build_info_buf);
104 if (ret != ERROR_OK)
105 return false;
107 LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf);
109 return target->rtos->symbols &&
110 target->rtos->symbols[CHROMIUM_EC_VAL_start_called].address;
113 static int chromium_ec_create(struct target *target)
115 struct chromium_ec_params *params;
116 size_t t;
118 for (t = 0; t < ARRAY_SIZE(chromium_ec_params_list); t++)
119 if (!strcmp(chromium_ec_params_list[t].target_name, target->type->name)) {
120 params = malloc(sizeof(*params));
121 if (!params) {
122 LOG_ERROR("Chromium-EC: out of memory");
123 return ERROR_FAIL;
126 memcpy(params, &chromium_ec_params_list[t], sizeof(*params));
127 target->rtos->rtos_specific_params = (void *)params;
128 target->rtos->current_thread = 0;
129 target->rtos->thread_details = NULL;
130 target->rtos->thread_count = 0;
132 LOG_INFO("Chromium-EC: Using target: %s", target->type->name);
133 return ERROR_OK;
136 LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name);
137 return ERROR_FAIL;
140 static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task)
142 if (!rtos || !rtos->symbols)
143 return ERROR_FAIL;
145 return target_read_u32(rtos->target,
146 rtos->symbols[CHROMIUM_EC_VAL_current_task].address,
147 current_task);
150 static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks)
152 uint32_t tasks_enabled;
153 int ret, t, found;
155 ret = target_read_u32(rtos->target,
156 rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address,
157 &tasks_enabled);
158 if (ret != ERROR_OK) {
159 LOG_ERROR("Failed to determine #of tasks");
160 return ret;
163 found = 0;
164 for (t = 0; t < CROS_EC_MAX_TASKS; t++)
165 if (tasks_enabled & BIT(t))
166 found++;
168 *num_tasks = found;
170 return ERROR_OK;
173 static int chromium_ec_update_threads(struct rtos *rtos)
175 uint32_t tasks_enabled, tasks_ready, start_called;
176 uint32_t current_task, thread_ptr, name_ptr;
177 char thread_str_buf[CROS_EC_MAX_NAME];
178 int ret, t, num_tasks, tasks_found;
179 struct chromium_ec_params *params;
180 uint8_t runtime_buf[8];
181 uint64_t runtime;
182 uint32_t events;
184 params = rtos->rtos_specific_params;
185 if (!params)
186 return ERROR_FAIL;
188 if (!rtos->symbols)
189 return ERROR_FAIL;
191 num_tasks = 0;
192 ret = chromium_ec_get_num_tasks(rtos, &num_tasks);
193 if (ret != ERROR_OK) {
194 LOG_ERROR("Failed to get number of tasks");
195 return ret;
198 current_task = 0;
199 ret = chromium_ec_get_current_task_ptr(rtos, &current_task);
200 if (ret != ERROR_OK) {
201 LOG_ERROR("Failed to get current task");
202 return ret;
204 LOG_DEBUG("Current task: %lx tasks_found: %d",
205 (unsigned long)current_task,
206 num_tasks);
208 /* set current task to what we read */
209 rtos->current_thread = current_task;
211 /* Nuke the old tasks */
212 rtos_free_threadlist(rtos);
214 /* One check if task switching has started ... */
215 start_called = 0;
216 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_start_called].address,
217 &start_called);
218 if (ret != ERROR_OK) {
219 LOG_ERROR("Failed to load start_called");
220 return ret;
223 if (!rtos->current_thread || !num_tasks || !start_called) {
224 num_tasks++;
226 rtos->thread_details = malloc(
227 sizeof(struct thread_detail) * num_tasks);
228 rtos->thread_details->threadid = 1;
229 rtos->thread_details->exists = true;
230 rtos->thread_details->extra_info_str = NULL;
231 rtos->thread_details->thread_name_str = strdup("Current Execution");
233 if (!num_tasks || !start_called) {
234 rtos->thread_count = 1;
235 return ERROR_OK;
237 } else {
238 /* create space for new thread details */
239 rtos->thread_details = malloc(
240 sizeof(struct thread_detail) * num_tasks);
243 tasks_enabled = 0;
244 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address,
245 &tasks_enabled);
246 if (ret != ERROR_OK) {
247 LOG_ERROR("Failed to load tasks_enabled");
248 return ret;
251 tasks_ready = 0;
252 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_ready].address,
253 &tasks_ready);
254 if (ret != ERROR_OK) {
255 LOG_ERROR("Failed to load tasks_ready");
256 return ret;
259 thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_tasks].address;
261 tasks_found = 0;
262 for (t = 0; t < CROS_EC_MAX_TASKS; t++) {
263 if (!(tasks_enabled & BIT(t)))
264 continue;
266 if (thread_ptr == current_task)
267 rtos->current_thread = thread_ptr;
269 rtos->thread_details[tasks_found].threadid = thread_ptr;
270 ret = target_read_u32(rtos->target,
271 rtos->symbols[CHROMIUM_EC_VAL_task_names].address +
272 params->ptr_size * t, &name_ptr);
273 if (ret != ERROR_OK) {
274 LOG_ERROR("Failed to read name_ptr");
275 return ret;
278 /* read name buffer */
279 ret = target_read_buffer(rtos->target, name_ptr, CROS_EC_MAX_NAME,
280 (uint8_t *)thread_str_buf);
281 if (ret != ERROR_OK) {
282 LOG_ERROR("Failed to read task name");
283 return ret;
286 /* sanitize string, gdb chokes on "<< idle >>" */
287 if (thread_str_buf[CROS_EC_MAX_NAME - 1] != '\0')
288 thread_str_buf[CROS_EC_MAX_NAME - 1] = '\0';
289 if (!strncmp(thread_str_buf, CROS_EC_IDLE_STRING, CROS_EC_MAX_NAME))
290 rtos->thread_details[tasks_found].thread_name_str = strdup("IDLE");
291 else
292 rtos->thread_details[tasks_found].thread_name_str = strdup(thread_str_buf);
294 events = 0;
295 ret = target_read_u32(rtos->target,
296 thread_ptr + params->task_offset_events,
297 &events);
298 if (ret != ERROR_OK)
299 LOG_ERROR("Failed to get task %d's events", t);
301 /* this is a bit kludgy but will do for now */
302 ret = target_read_buffer(rtos->target,
303 thread_ptr + params->task_offset_runtime,
304 sizeof(runtime_buf), runtime_buf);
305 if (ret != ERROR_OK)
306 LOG_ERROR("Failed to get task %d's runtime", t);
307 runtime = target_buffer_get_u64(rtos->target, runtime_buf);
309 /* Priority is simply the positon in the array */
310 if (thread_ptr == current_task)
311 snprintf(thread_str_buf, sizeof(thread_str_buf),
312 "State: Running, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
313 t, events, runtime);
314 else
315 snprintf(thread_str_buf, sizeof(thread_str_buf),
316 "State: %s, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
317 tasks_ready & BIT(t) ? "Ready" : "Waiting", t,
318 events, runtime);
320 rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf);
321 rtos->thread_details[tasks_found].exists = true;
323 thread_ptr += params->task_offset_next;
325 tasks_found++;
328 rtos->thread_count = tasks_found;
330 return ERROR_OK;
333 static int chromium_ec_get_thread_reg_list(struct rtos *rtos,
334 threadid_t threadid,
335 struct rtos_reg **reg_list,
336 int *num_regs)
338 struct chromium_ec_params *params = rtos->rtos_specific_params;
339 uint32_t stack_ptr = 0;
340 int ret, t;
342 for (t = 0; t < rtos->thread_count; t++)
343 if (threadid == rtos->thread_details[t].threadid)
344 break;
346 /* if we didn't find threadid, bail */
347 if (t == rtos->thread_count)
348 return ERROR_FAIL;
350 ret = target_read_u32(rtos->target,
351 rtos->symbols[CHROMIUM_EC_VAL_tasks].address +
352 params->task_offset_next * t,
353 &stack_ptr);
354 if (ret != ERROR_OK) {
355 LOG_ERROR("Failed to load TCB");
356 return ret;
359 return rtos_generic_stack_read(rtos->target, params->stacking,
360 stack_ptr, reg_list, num_regs);
363 static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
365 size_t s;
367 *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
368 sizeof(symbol_table_elem_t));
369 if (!(*symbol_list)) {
370 LOG_ERROR("Chromium-EC: out of memory");
371 return ERROR_FAIL;
374 for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++)
375 (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s];
377 return ERROR_OK;
380 const struct rtos_type chromium_ec_rtos = {
381 .name = "Chromium-EC",
382 .detect_rtos = chromium_ec_detect_rtos,
383 .create = chromium_ec_create,
384 .update_threads = chromium_ec_update_threads,
385 .get_thread_reg_list = chromium_ec_get_thread_reg_list,
386 .get_symbol_list_to_lookup = chromium_ec_get_symbol_list_to_lookup,