target/xtensa: avoid IHI for writes to non-executable memory
[openocd.git] / src / rtos / chromium-ec.c
bloba95969e345a2bb17659138eec01f8a2c051afc79
1 // SPDX-License-Identifier: GPL-2.0-only
3 /*
4 * Copyright (c) 2018 National Instruments Corp
5 * Author: Moritz Fischer <moritz.fischer@ettus.com>
7 * Chromium-EC RTOS Task Awareness
8 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
14 #include <helper/bits.h>
15 #include <rtos/rtos.h>
16 #include <target/target.h>
17 #include <target/target_type.h>
19 #include "rtos_standard_stackings.h"
21 #define CROS_EC_MAX_TASKS 32
22 #define CROS_EC_MAX_NAME 200
23 #define CROS_EC_IDLE_STRING "<< idle >>"
25 struct chromium_ec_params {
26 const char *target_name;
27 size_t ptr_size;
28 off_t task_offset_next;
29 off_t task_offset_sp;
30 off_t task_offset_events;
31 off_t task_offset_runtime;
32 const struct rtos_register_stacking *stacking;
35 static const struct chromium_ec_params chromium_ec_params_list[] = {
37 .target_name = "hla_target",
38 .ptr_size = 4,
39 .task_offset_next = 24,
40 .task_offset_sp = 0,
41 .task_offset_events = 4,
42 .task_offset_runtime = 8,
43 .stacking = &rtos_standard_cortex_m3_stacking,
47 .target_name = "cortex_m",
48 .ptr_size = 4,
49 .task_offset_next = 24,
50 .task_offset_sp = 0,
51 .task_offset_events = 4,
52 .task_offset_runtime = 8,
53 .stacking = &rtos_standard_cortex_m3_stacking,
57 static const char * const chromium_ec_symbol_list[] = {
58 "start_called",
59 "current_task",
60 "tasks",
61 "tasks_enabled",
62 "tasks_ready",
63 "task_names",
64 "build_info",
65 NULL,
68 enum chromium_ec_symbol_values {
69 CHROMIUM_EC_VAL_START_CALLED = 0,
70 CHROMIUM_EC_VAL_CURRENT_TASK,
71 CHROMIUM_EC_VAL_TASKS,
72 CHROMIUM_EC_VAL_TASKS_ENABLED,
73 CHROMIUM_EC_VAL_TASKS_READY,
74 CHROMIUM_EC_VAL_TASK_NAMES,
75 CHROMIUM_EC_VAL_BUILD_INFO,
77 CHROMIUM_EC_VAL_COUNT,
80 #define CROS_EC_MAX_BUILDINFO 512
82 static bool chromium_ec_detect_rtos(struct target *target)
84 char build_info_buf[CROS_EC_MAX_BUILDINFO];
85 enum chromium_ec_symbol_values sym;
86 int ret;
88 if (!target || !target->rtos || !target->rtos->symbols)
89 return false;
91 for (sym = CHROMIUM_EC_VAL_START_CALLED;
92 sym < CHROMIUM_EC_VAL_COUNT; sym++) {
93 if (target->rtos->symbols[sym].address) {
94 LOG_DEBUG("Chromium-EC: Symbol \"%s\" found",
95 chromium_ec_symbol_list[sym]);
96 } else {
97 LOG_ERROR("Chromium-EC: Symbol \"%s\" missing",
98 chromium_ec_symbol_list[sym]);
99 return false;
103 ret = target_read_buffer(target,
104 target->rtos->symbols[CHROMIUM_EC_VAL_BUILD_INFO].address,
105 sizeof(build_info_buf),
106 (uint8_t *)build_info_buf);
108 if (ret != ERROR_OK)
109 return false;
111 LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf);
113 return target->rtos->symbols &&
114 target->rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address;
117 static int chromium_ec_create(struct target *target)
119 struct chromium_ec_params *params;
120 size_t t;
122 for (t = 0; t < ARRAY_SIZE(chromium_ec_params_list); t++)
123 if (!strcmp(chromium_ec_params_list[t].target_name, target->type->name)) {
124 params = malloc(sizeof(*params));
125 if (!params) {
126 LOG_ERROR("Chromium-EC: out of memory");
127 return ERROR_FAIL;
130 memcpy(params, &chromium_ec_params_list[t], sizeof(*params));
131 target->rtos->rtos_specific_params = (void *)params;
132 target->rtos->current_thread = 0;
133 target->rtos->thread_details = NULL;
134 target->rtos->thread_count = 0;
136 LOG_INFO("Chromium-EC: Using target: %s", target->type->name);
137 return ERROR_OK;
140 LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name);
141 return ERROR_FAIL;
144 static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task)
146 if (!rtos || !rtos->symbols)
147 return ERROR_FAIL;
149 return target_read_u32(rtos->target,
150 rtos->symbols[CHROMIUM_EC_VAL_CURRENT_TASK].address,
151 current_task);
154 static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks)
156 uint32_t tasks_enabled;
157 int ret, t, found;
159 ret = target_read_u32(rtos->target,
160 rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address,
161 &tasks_enabled);
162 if (ret != ERROR_OK) {
163 LOG_ERROR("Failed to determine #of tasks");
164 return ret;
167 found = 0;
168 for (t = 0; t < CROS_EC_MAX_TASKS; t++)
169 if (tasks_enabled & BIT(t))
170 found++;
172 *num_tasks = found;
174 return ERROR_OK;
177 static int chromium_ec_update_threads(struct rtos *rtos)
179 uint32_t tasks_enabled, tasks_ready, start_called;
180 uint32_t current_task, thread_ptr, name_ptr;
181 char thread_str_buf[CROS_EC_MAX_NAME];
182 int ret, t, num_tasks, tasks_found;
183 struct chromium_ec_params *params;
184 uint8_t runtime_buf[8];
185 uint64_t runtime;
186 uint32_t events;
188 params = rtos->rtos_specific_params;
189 if (!params)
190 return ERROR_FAIL;
192 if (!rtos->symbols)
193 return ERROR_FAIL;
195 num_tasks = 0;
196 ret = chromium_ec_get_num_tasks(rtos, &num_tasks);
197 if (ret != ERROR_OK) {
198 LOG_ERROR("Failed to get number of tasks");
199 return ret;
202 current_task = 0;
203 ret = chromium_ec_get_current_task_ptr(rtos, &current_task);
204 if (ret != ERROR_OK) {
205 LOG_ERROR("Failed to get current task");
206 return ret;
208 LOG_DEBUG("Current task: %lx tasks_found: %d",
209 (unsigned long)current_task,
210 num_tasks);
212 /* set current task to what we read */
213 rtos->current_thread = current_task;
215 /* Nuke the old tasks */
216 rtos_free_threadlist(rtos);
218 /* One check if task switching has started ... */
219 start_called = 0;
220 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address,
221 &start_called);
222 if (ret != ERROR_OK) {
223 LOG_ERROR("Failed to load start_called");
224 return ret;
227 if (!rtos->current_thread || !num_tasks || !start_called) {
228 num_tasks++;
230 rtos->thread_details = malloc(
231 sizeof(struct thread_detail) * num_tasks);
232 rtos->thread_details->threadid = 1;
233 rtos->thread_details->exists = true;
234 rtos->thread_details->extra_info_str = NULL;
235 rtos->thread_details->thread_name_str = strdup("Current Execution");
237 if (!num_tasks || !start_called) {
238 rtos->thread_count = 1;
239 return ERROR_OK;
241 } else {
242 /* create space for new thread details */
243 rtos->thread_details = malloc(
244 sizeof(struct thread_detail) * num_tasks);
247 tasks_enabled = 0;
248 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_ENABLED].address,
249 &tasks_enabled);
250 if (ret != ERROR_OK) {
251 LOG_ERROR("Failed to load tasks_enabled");
252 return ret;
255 tasks_ready = 0;
256 ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_TASKS_READY].address,
257 &tasks_ready);
258 if (ret != ERROR_OK) {
259 LOG_ERROR("Failed to load tasks_ready");
260 return ret;
263 thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_TASKS].address;
265 tasks_found = 0;
266 for (t = 0; t < CROS_EC_MAX_TASKS; t++) {
267 if (!(tasks_enabled & BIT(t)))
268 continue;
270 if (thread_ptr == current_task)
271 rtos->current_thread = thread_ptr;
273 rtos->thread_details[tasks_found].threadid = thread_ptr;
274 ret = target_read_u32(rtos->target,
275 rtos->symbols[CHROMIUM_EC_VAL_TASK_NAMES].address +
276 params->ptr_size * t, &name_ptr);
277 if (ret != ERROR_OK) {
278 LOG_ERROR("Failed to read name_ptr");
279 return ret;
282 /* read name buffer */
283 ret = target_read_buffer(rtos->target, name_ptr, CROS_EC_MAX_NAME,
284 (uint8_t *)thread_str_buf);
285 if (ret != ERROR_OK) {
286 LOG_ERROR("Failed to read task name");
287 return ret;
290 /* sanitize string, gdb chokes on "<< idle >>" */
291 if (thread_str_buf[CROS_EC_MAX_NAME - 1] != '\0')
292 thread_str_buf[CROS_EC_MAX_NAME - 1] = '\0';
293 if (!strncmp(thread_str_buf, CROS_EC_IDLE_STRING, CROS_EC_MAX_NAME))
294 rtos->thread_details[tasks_found].thread_name_str = strdup("IDLE");
295 else
296 rtos->thread_details[tasks_found].thread_name_str = strdup(thread_str_buf);
298 events = 0;
299 ret = target_read_u32(rtos->target,
300 thread_ptr + params->task_offset_events,
301 &events);
302 if (ret != ERROR_OK)
303 LOG_ERROR("Failed to get task %d's events", t);
305 /* this is a bit kludgy but will do for now */
306 ret = target_read_buffer(rtos->target,
307 thread_ptr + params->task_offset_runtime,
308 sizeof(runtime_buf), runtime_buf);
309 if (ret != ERROR_OK)
310 LOG_ERROR("Failed to get task %d's runtime", t);
311 runtime = target_buffer_get_u64(rtos->target, runtime_buf);
313 /* Priority is simply the position in the array */
314 if (thread_ptr == current_task)
315 snprintf(thread_str_buf, sizeof(thread_str_buf),
316 "State: Running, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
317 t, events, runtime);
318 else
319 snprintf(thread_str_buf, sizeof(thread_str_buf),
320 "State: %s, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
321 tasks_ready & BIT(t) ? "Ready" : "Waiting", t,
322 events, runtime);
324 rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf);
325 rtos->thread_details[tasks_found].exists = true;
327 thread_ptr += params->task_offset_next;
329 tasks_found++;
332 rtos->thread_count = tasks_found;
334 return ERROR_OK;
337 static int chromium_ec_get_thread_reg_list(struct rtos *rtos,
338 threadid_t threadid,
339 struct rtos_reg **reg_list,
340 int *num_regs)
342 struct chromium_ec_params *params = rtos->rtos_specific_params;
343 uint32_t stack_ptr = 0;
344 int ret, t;
346 for (t = 0; t < rtos->thread_count; t++)
347 if (threadid == rtos->thread_details[t].threadid)
348 break;
350 /* if we didn't find threadid, bail */
351 if (t == rtos->thread_count)
352 return ERROR_FAIL;
354 ret = target_read_u32(rtos->target,
355 rtos->symbols[CHROMIUM_EC_VAL_TASKS].address +
356 params->task_offset_next * t,
357 &stack_ptr);
358 if (ret != ERROR_OK) {
359 LOG_ERROR("Failed to load TCB");
360 return ret;
363 return rtos_generic_stack_read(rtos->target, params->stacking,
364 stack_ptr, reg_list, num_regs);
367 static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
369 size_t s;
371 *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
372 sizeof(struct symbol_table_elem));
373 if (!(*symbol_list)) {
374 LOG_ERROR("Chromium-EC: out of memory");
375 return ERROR_FAIL;
378 for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++)
379 (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s];
381 return ERROR_OK;
384 const struct rtos_type chromium_ec_rtos = {
385 .name = "Chromium-EC",
386 .detect_rtos = chromium_ec_detect_rtos,
387 .create = chromium_ec_create,
388 .update_threads = chromium_ec_update_threads,
389 .get_thread_reg_list = chromium_ec_get_thread_reg_list,
390 .get_symbol_list_to_lookup = chromium_ec_get_symbol_list_to_lookup,