rtos: convert CamelCase enum in uppercase
[fw/openocd] / 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 position 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(struct symbol_table_elem *symbol_list[])
364 {
365         size_t s;
366
367         *symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
368                               sizeof(struct symbol_table_elem));
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 };