rtos: Add RTOS task awareness for Chromium-EC
[openocd.git] / src / rtos / chromium-ec.c
1 /*
2 * SPDX-License-Identifier: GPL-2.0
3 *
4 * Copyright (c) 2018 National Instruments Corp
5 * Author: Moritz Fischer <moritz.fischer@ettus.com>
6 *
7 * Chromium-EC RTOS Task Awareness
8 */
9
10 #include <rtos/rtos.h>
11 #include <target/target.h>
12 #include <target/target_type.h>
13
14 #include "rtos_standard_stackings.h"
15
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))
20
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;
29 };
30
31 static const struct chromium_ec_params chromium_ec_params_list[] = {
32 {
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,
40
41 },
42 {
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,
50 },
51 };
52
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,
62 };
63
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,
72
73 CHROMIUM_EC_VAL_COUNT,
74 };
75
76 #define CROS_EC_MAX_BUILDINFO 512
77
78 static bool chromium_ec_detect_rtos(struct target *target)
79 {
80 char build_info_buf[CROS_EC_MAX_BUILDINFO];
81 enum chromium_ec_symbol_values sym;
82 int ret;
83
84 if (!target || !target->rtos || !target->rtos->symbols)
85 return false;
86
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;
96 }
97 }
98
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);
103
104 if (ret != ERROR_OK)
105 return false;
106
107 LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf);
108
109 return target->rtos->symbols &&
110 target->rtos->symbols[CHROMIUM_EC_VAL_start_called].address;
111 }
112
113 static int chromium_ec_create(struct target *target)
114 {
115 struct chromium_ec_params *params;
116 size_t t;
117
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;
124 }
125
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;
131
132 LOG_INFO("Chromium-EC: Using target: %s", target->type->name);
133 return ERROR_OK;
134 }
135
136 LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name);
137 return ERROR_FAIL;
138 }
139
140 static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task)
141 {
142 if (!rtos || !rtos->symbols)
143 return ERROR_FAIL;
144
145 return target_read_u32(rtos->target,
146 rtos->symbols[CHROMIUM_EC_VAL_current_task].address,
147 current_task);
148 }
149
150 static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks)
151 {
152 uint32_t tasks_enabled;
153 int ret, t, found;
154
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;
161 }
162
163 found = 0;
164 for (t = 0; t < CROS_EC_MAX_TASKS; t++)
165 if (tasks_enabled & BIT(t))
166 found++;
167
168 *num_tasks = found;
169
170 return ERROR_OK;
171 }
172
173 static int chromium_ec_update_threads(struct rtos *rtos)
174 {
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;
183
184 params = rtos->rtos_specific_params;
185 if (!params)
186 return ERROR_FAIL;
187
188 if (!rtos->symbols)
189 return ERROR_FAIL;
190
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;
196 }
197
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;
203 }
204 LOG_DEBUG("Current task: %lx tasks_found: %d",
205 (unsigned long)current_task,
206 num_tasks);
207
208 /* set current task to what we read */
209 rtos->current_thread = current_task;
210
211 /* Nuke the old tasks */
212 rtos_free_threadlist(rtos);
213
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;
221 }
222
223 if (!rtos->current_thread || !num_tasks || !start_called) {
224 num_tasks++;
225
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");
232
233 if (!num_tasks || !start_called) {
234 rtos->thread_count = 1;
235 return ERROR_OK;
236 }
237 } else {
238 /* create space for new thread details */
239 rtos->thread_details = malloc(
240 sizeof(struct thread_detail) * num_tasks);
241 }
242
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;
249 }
250
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;
257 }
258
259 thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_tasks].address;
260
261 tasks_found = 0;
262 for (t = 0; t < CROS_EC_MAX_TASKS; t++) {
263 if (!(tasks_enabled & BIT(t)))
264 continue;
265
266 if (thread_ptr == current_task)
267 rtos->current_thread = thread_ptr;
268
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;
276 }
277
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;
284 }
285
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);
293
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);
300
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);
308
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);
319
320 rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf);
321 rtos->thread_details[tasks_found].exists = true;
322
323 thread_ptr += params->task_offset_next;
324
325 tasks_found++;
326 }
327
328 rtos->thread_count = tasks_found;
329
330 return ERROR_OK;
331 }
332
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)
337 {
338 struct chromium_ec_params *params = rtos->rtos_specific_params;
339 uint32_t stack_ptr = 0;
340 int ret, t;
341
342 for (t = 0; t < rtos->thread_count; t++)
343 if (threadid == rtos->thread_details[t].threadid)
344 break;
345
346 /* if we didn't find threadid, bail */
347 if (t == rtos->thread_count)
348 return ERROR_FAIL;
349
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;
357 }
358
359 return rtos_generic_stack_read(rtos->target, params->stacking,
360 stack_ptr, reg_list, num_regs);
361 }
362
363 static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
364 {
365 size_t s;
366
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;
372 }
373
374 for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++)
375 (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s];
376
377 return ERROR_OK;
378 }
379
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,
387 };

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)