782a4620a922936fd6c76972182a44f301f6667f
[fw/openocd] / src / rtos / chromium-ec.c
1 /* SPDX-License-Identifier: GPL-2.0-only */
2
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 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <helper/bits.h>
15 #include <rtos/rtos.h>
16 #include <target/target.h>
17 #include <target/target_type.h>
18
19 #include "rtos_standard_stackings.h"
20
21 #define CROS_EC_MAX_TASKS 32
22 #define CROS_EC_MAX_NAME 200
23 #define CROS_EC_IDLE_STRING "<< idle >>"
24
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;
33 };
34
35 static const struct chromium_ec_params chromium_ec_params_list[] = {
36         {
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,
44
45         },
46         {
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,
54         },
55 };
56
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,
66 };
67
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,
76
77         CHROMIUM_EC_VAL_COUNT,
78 };
79
80 #define CROS_EC_MAX_BUILDINFO 512
81
82 static bool chromium_ec_detect_rtos(struct target *target)
83 {
84         char build_info_buf[CROS_EC_MAX_BUILDINFO];
85         enum chromium_ec_symbol_values sym;
86         int ret;
87
88         if (!target || !target->rtos || !target->rtos->symbols)
89                 return false;
90
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;
100                 }
101         }
102
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);
107
108         if (ret != ERROR_OK)
109                 return false;
110
111         LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf);
112
113         return target->rtos->symbols &&
114                target->rtos->symbols[CHROMIUM_EC_VAL_START_CALLED].address;
115 }
116
117 static int chromium_ec_create(struct target *target)
118 {
119         struct chromium_ec_params *params;
120         size_t t;
121
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;
128                         }
129
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;
135
136                         LOG_INFO("Chromium-EC: Using target: %s", target->type->name);
137                         return ERROR_OK;
138                 }
139
140         LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name);
141         return ERROR_FAIL;
142 }
143
144 static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task)
145 {
146         if (!rtos || !rtos->symbols)
147                 return ERROR_FAIL;
148
149         return target_read_u32(rtos->target,
150                                rtos->symbols[CHROMIUM_EC_VAL_CURRENT_TASK].address,
151                                current_task);
152 }
153
154 static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks)
155 {
156         uint32_t tasks_enabled;
157         int ret, t, found;
158
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;
165         }
166
167         found = 0;
168         for (t = 0; t < CROS_EC_MAX_TASKS; t++)
169                 if (tasks_enabled & BIT(t))
170                         found++;
171
172         *num_tasks = found;
173
174         return ERROR_OK;
175 }
176
177 static int chromium_ec_update_threads(struct rtos *rtos)
178 {
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;
187
188         params = rtos->rtos_specific_params;
189         if (!params)
190                 return ERROR_FAIL;
191
192         if (!rtos->symbols)
193                 return ERROR_FAIL;
194
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;
200         }
201
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;
207         }
208         LOG_DEBUG("Current task: %lx tasks_found: %d",
209                   (unsigned long)current_task,
210                   num_tasks);
211
212         /* set current task to what we read */
213         rtos->current_thread = current_task;
214
215         /* Nuke the old tasks */
216         rtos_free_threadlist(rtos);
217
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;
225         }
226
227         if (!rtos->current_thread || !num_tasks || !start_called) {
228                 num_tasks++;
229
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");
236
237                 if (!num_tasks || !start_called) {
238                         rtos->thread_count = 1;
239                         return ERROR_OK;
240                 }
241         } else {
242                 /* create space for new thread details */
243                 rtos->thread_details = malloc(
244                                 sizeof(struct thread_detail) * num_tasks);
245         }
246
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;
253         }
254
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;
261         }
262
263         thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_TASKS].address;
264
265         tasks_found = 0;
266         for (t = 0; t < CROS_EC_MAX_TASKS; t++) {
267                 if (!(tasks_enabled & BIT(t)))
268                         continue;
269
270                 if (thread_ptr == current_task)
271                         rtos->current_thread = thread_ptr;
272
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;
280                 }
281
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;
288                 }
289
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);
297
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);
304
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);
312
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);
323
324                 rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf);
325                 rtos->thread_details[tasks_found].exists = true;
326
327                 thread_ptr += params->task_offset_next;
328
329                 tasks_found++;
330         }
331
332         rtos->thread_count = tasks_found;
333
334         return ERROR_OK;
335 }
336
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)
341 {
342         struct chromium_ec_params *params = rtos->rtos_specific_params;
343         uint32_t stack_ptr = 0;
344         int ret, t;
345
346         for (t = 0; t < rtos->thread_count; t++)
347                 if (threadid == rtos->thread_details[t].threadid)
348                         break;
349
350         /* if we didn't find threadid, bail */
351         if (t == rtos->thread_count)
352                 return ERROR_FAIL;
353
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;
361         }
362
363         return rtos_generic_stack_read(rtos->target, params->stacking,
364                                        stack_ptr, reg_list, num_regs);
365 }
366
367 static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
368 {
369         size_t s;
370
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;
376         }
377
378         for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++)
379                 (*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s];
380
381         return ERROR_OK;
382 }
383
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,
391 };