1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (c) 2018 National Instruments Corp
5 * Author: Moritz Fischer <moritz.fischer@ettus.com>
7 * Chromium-EC RTOS Task Awareness
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
;
28 off_t task_offset_next
;
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",
39 .task_offset_next
= 24,
41 .task_offset_events
= 4,
42 .task_offset_runtime
= 8,
43 .stacking
= &rtos_standard_cortex_m3_stacking
,
47 .target_name
= "cortex_m",
49 .task_offset_next
= 24,
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
[] = {
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
;
88 if (!target
|| !target
->rtos
|| !target
->rtos
->symbols
)
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
]);
97 LOG_ERROR("Chromium-EC: Symbol \"%s\" missing",
98 chromium_ec_symbol_list
[sym
]);
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
);
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
;
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
));
126 LOG_ERROR("Chromium-EC: out of memory");
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
);
140 LOG_ERROR("Chromium-EC: target not supported: %s", target
->type
->name
);
144 static int chromium_ec_get_current_task_ptr(struct rtos
*rtos
, uint32_t *current_task
)
146 if (!rtos
|| !rtos
->symbols
)
149 return target_read_u32(rtos
->target
,
150 rtos
->symbols
[CHROMIUM_EC_VAL_CURRENT_TASK
].address
,
154 static int chromium_ec_get_num_tasks(struct rtos
*rtos
, int *num_tasks
)
156 uint32_t tasks_enabled
;
159 ret
= target_read_u32(rtos
->target
,
160 rtos
->symbols
[CHROMIUM_EC_VAL_TASKS_ENABLED
].address
,
162 if (ret
!= ERROR_OK
) {
163 LOG_ERROR("Failed to determine #of tasks");
168 for (t
= 0; t
< CROS_EC_MAX_TASKS
; t
++)
169 if (tasks_enabled
& BIT(t
))
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];
188 params
= rtos
->rtos_specific_params
;
196 ret
= chromium_ec_get_num_tasks(rtos
, &num_tasks
);
197 if (ret
!= ERROR_OK
) {
198 LOG_ERROR("Failed to get number of tasks");
203 ret
= chromium_ec_get_current_task_ptr(rtos
, ¤t_task
);
204 if (ret
!= ERROR_OK
) {
205 LOG_ERROR("Failed to get current task");
208 LOG_DEBUG("Current task: %lx tasks_found: %d",
209 (unsigned long)current_task
,
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 ... */
220 ret
= target_read_u32(rtos
->target
, rtos
->symbols
[CHROMIUM_EC_VAL_START_CALLED
].address
,
222 if (ret
!= ERROR_OK
) {
223 LOG_ERROR("Failed to load start_called");
227 if (!rtos
->current_thread
|| !num_tasks
|| !start_called
) {
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;
242 /* create space for new thread details */
243 rtos
->thread_details
= malloc(
244 sizeof(struct thread_detail
) * num_tasks
);
248 ret
= target_read_u32(rtos
->target
, rtos
->symbols
[CHROMIUM_EC_VAL_TASKS_ENABLED
].address
,
250 if (ret
!= ERROR_OK
) {
251 LOG_ERROR("Failed to load tasks_enabled");
256 ret
= target_read_u32(rtos
->target
, rtos
->symbols
[CHROMIUM_EC_VAL_TASKS_READY
].address
,
258 if (ret
!= ERROR_OK
) {
259 LOG_ERROR("Failed to load tasks_ready");
263 thread_ptr
= rtos
->symbols
[CHROMIUM_EC_VAL_TASKS
].address
;
266 for (t
= 0; t
< CROS_EC_MAX_TASKS
; t
++) {
267 if (!(tasks_enabled
& BIT(t
)))
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");
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");
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");
296 rtos
->thread_details
[tasks_found
].thread_name_str
= strdup(thread_str_buf
);
299 ret
= target_read_u32(rtos
->target
,
300 thread_ptr
+ params
->task_offset_events
,
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
);
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",
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
,
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
;
332 rtos
->thread_count
= tasks_found
;
337 static int chromium_ec_get_thread_reg_list(struct rtos
*rtos
,
339 struct rtos_reg
**reg_list
,
342 struct chromium_ec_params
*params
= rtos
->rtos_specific_params
;
343 uint32_t stack_ptr
= 0;
346 for (t
= 0; t
< rtos
->thread_count
; t
++)
347 if (threadid
== rtos
->thread_details
[t
].threadid
)
350 /* if we didn't find threadid, bail */
351 if (t
== rtos
->thread_count
)
354 ret
= target_read_u32(rtos
->target
,
355 rtos
->symbols
[CHROMIUM_EC_VAL_TASKS
].address
+
356 params
->task_offset_next
* t
,
358 if (ret
!= ERROR_OK
) {
359 LOG_ERROR("Failed to load TCB");
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
[])
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");
378 for (s
= 0; s
< ARRAY_SIZE(chromium_ec_symbol_list
); s
++)
379 (*symbol_list
)[s
].symbol_name
= chromium_ec_symbol_list
[s
];
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
,