rtos: Support rt-kernel
[openocd.git] / src / rtos / rtkernel.c
blobba1de25172bac7871015f80f909ca3479c117f84
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2016-2023 by Andreas Fritiofson *
5 * andreas.fritiofson@gmail.com *
6 ***************************************************************************/
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "rtos.h"
17 #include "helper/log.h"
18 #include "helper/types.h"
19 #include "rtos_standard_stackings.h"
20 #include "target/armv7m.h"
21 #include "target/cortex_m.h"
23 #define ST_DEAD BIT(0) /* Task is waiting to be deleted */
24 #define ST_WAIT BIT(1) /* Task is blocked: */
25 #define ST_SEM BIT(2) /* on semaphore */
26 #define ST_MTX BIT(3) /* on mutex */
27 #define ST_SIG BIT(4) /* on signal */
28 #define ST_DLY BIT(5) /* on timer */
29 #define ST_FLAG BIT(6) /* on flag */
30 #define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */
31 #define ST_MBOX BIT(8) /* on mailbox */
32 #define ST_STP BIT(9) /* self stopped */
33 #define ST_SUSPEND BIT(10) /* Task is suspended */
34 #define ST_TT BIT(11) /* Time triggered task */
35 #define ST_TT_YIELD BIT(12) /* Time triggered task that yields */
36 #define ST_CREATE BIT(13) /* Task was created by task_create() */
38 struct rtkernel_params {
39 const char *target_name;
40 const struct rtos_register_stacking *stacking_info_cm3;
41 const struct rtos_register_stacking *stacking_info_cm4f;
42 const struct rtos_register_stacking *stacking_info_cm4f_fpu;
45 static const struct rtkernel_params rtkernel_params_list[] = {
47 "cortex_m", /* target_name */
48 &rtos_standard_cortex_m3_stacking, /* stacking_info */
49 &rtos_standard_cortex_m4f_stacking,
50 &rtos_standard_cortex_m4f_fpu_stacking,
53 "hla_target", /* target_name */
54 &rtos_standard_cortex_m3_stacking, /* stacking_info */
55 &rtos_standard_cortex_m4f_stacking,
56 &rtos_standard_cortex_m4f_fpu_stacking,
60 enum rtkernel_symbol_values {
61 sym_os_state = 0,
62 sym___off_os_state2chain = 1,
63 sym___off_os_state2current = 2,
64 sym___off_task2chain = 3,
65 sym___off_task2magic = 4,
66 sym___off_task2stack = 5,
67 sym___off_task2state = 6,
68 sym___off_task2name = 7,
69 sym___val_task_magic = 8,
72 struct symbols {
73 const char *name;
74 bool optional;
77 static const struct symbols rtkernel_symbol_list[] = {
78 { "os_state", false },
79 { "__off_os_state2chain", false },
80 { "__off_os_state2current", false },
81 { "__off_task2chain", false },
82 { "__off_task2magic", false },
83 { "__off_task2stack", false },
84 { "__off_task2state", false },
85 { "__off_task2name", false },
86 { "__val_task_magic", false },
87 { NULL, false }
90 static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size)
92 void *new_ptr = malloc(new_size);
94 if (new_ptr) {
95 memcpy(new_ptr, ptr, MIN(old_size, new_size));
96 free(ptr);
99 return new_ptr;
102 static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task)
104 int retval;
105 int new_thread_count = rtos->thread_count + 1;
106 struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details,
107 rtos->thread_count * sizeof(struct thread_detail),
108 new_thread_count * sizeof(struct thread_detail));
109 if (!new_thread_details) {
110 LOG_ERROR("Error growing memory to %d threads", new_thread_count);
111 return ERROR_FAIL;
113 rtos->thread_details = new_thread_details;
114 struct thread_detail *thread = &new_thread_details[rtos->thread_count];
116 *thread = (struct thread_detail){ .threadid = task, .exists = true };
118 /* Read the task name */
119 uint32_t name;
120 retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2name].address, &name);
121 if (retval != ERROR_OK) {
122 LOG_ERROR("Could not read task name pointer from target");
123 return retval;
125 uint8_t tmp_str[33];
126 retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str);
127 if (retval != ERROR_OK) {
128 LOG_ERROR("Error reading task name from target");
129 return retval;
131 tmp_str[sizeof(tmp_str) - 1] = '\0';
132 LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str);
134 if (tmp_str[0] != '\0')
135 thread->thread_name_str = strdup((char *)tmp_str);
136 else
137 thread->thread_name_str = strdup("No Name");
139 /* Read the task state */
140 uint16_t state;
141 retval = target_read_u16(rtos->target, task + rtos->symbols[sym___off_task2state].address, &state);
142 if (retval != ERROR_OK) {
143 LOG_ERROR("Could not read task state from target");
144 return retval;
147 LOG_DEBUG("task state 0x%" PRIx16, state);
149 char state_str[64] = "";
150 if (state & ST_TT)
151 strcat(state_str, "TT|");
152 if (task == current_task) {
153 strcat(state_str, "RUN");
154 } else {
155 if (state & (ST_TT | ST_TT_YIELD))
156 strcat(state_str, "YIELD");
157 else if (state & ST_DEAD)
158 strcat(state_str, "DEAD");
159 else if (state & ST_WAIT)
160 strcat(state_str, "WAIT");
161 else if (state & ST_SUSPEND)
162 strcat(state_str, "SUSP");
163 else
164 strcat(state_str, "READY");
166 if (state & ST_SEM)
167 strcat(state_str, "|SEM");
168 if (state & ST_MTX)
169 strcat(state_str, "|MTX");
170 if (state & ST_SIG)
171 strcat(state_str, "|SIG");
172 if (state & ST_DLY)
173 strcat(state_str, "|DLY");
174 if ((state & ST_FLAG) || (state & ST_FLAG_ALL))
175 strcat(state_str, "|FLAG");
176 if (state & ST_FLAG_ALL)
177 strcat(state_str, "_ALL");
178 if (state & ST_MBOX)
179 strcat(state_str, "|MBOX");
180 if (state & ST_STP)
181 strcat(state_str, "|STP");
183 thread->extra_info_str = strdup(state_str);
185 rtos->thread_count = new_thread_count;
186 if (task == current_task)
187 rtos->current_thread = task;
188 return ERROR_OK;
191 static int rtkernel_verify_task(struct rtos *rtos, uint32_t task)
193 int retval;
194 uint32_t magic;
195 retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic);
196 if (retval != ERROR_OK) {
197 LOG_ERROR("Could not read task magic from target");
198 return retval;
200 if (magic != rtos->symbols[sym___val_task_magic].address) {
201 LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic);
202 return ERROR_FAIL;
204 return retval;
207 static int rtkernel_update_threads(struct rtos *rtos)
209 /* wipe out previous thread details if any */
210 /* do this first because rtos layer does not check our retval */
211 rtos_free_threadlist(rtos);
212 rtos->current_thread = 0;
214 if (!rtos->symbols) {
215 LOG_ERROR("No symbols for rt-kernel");
216 return -3;
219 /* read the current task */
220 uint32_t current_task;
221 int retval = target_read_u32(rtos->target,
222 rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2current].address,
223 &current_task);
224 if (retval != ERROR_OK) {
225 LOG_ERROR("Error reading current task");
226 return retval;
228 LOG_DEBUG("current task is 0x%" PRIx32, current_task);
230 retval = rtkernel_verify_task(rtos, current_task);
231 if (retval != ERROR_OK) {
232 LOG_ERROR("Current task is invalid");
233 return retval;
236 /* loop through kernel task list */
237 uint32_t chain = rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2chain].address;
238 LOG_DEBUG("chain start at 0x%" PRIx32, chain);
240 uint32_t next = chain;
241 for (;;) {
242 retval = target_read_u32(rtos->target, next, &next);
243 if (retval != ERROR_OK) {
244 LOG_ERROR("Could not read rt-kernel data structure from target");
245 return retval;
247 LOG_DEBUG("next entry at 0x%" PRIx32, next);
248 if (next == chain) {
249 LOG_DEBUG("end of chain detected");
250 break;
252 uint32_t task = next - rtos->symbols[sym___off_task2chain].address;
253 LOG_DEBUG("found task at 0x%" PRIx32, task);
255 retval = rtkernel_verify_task(rtos, task);
256 if (retval != ERROR_OK) {
257 LOG_ERROR("Invalid task found");
258 return retval;
261 retval = rtkernel_add_task(rtos, task, current_task);
262 if (retval != ERROR_OK) {
263 LOG_ERROR("Could not add task to rtos system");
264 return retval;
267 return ERROR_OK;
270 static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
271 struct rtos_reg **reg_list, int *num_regs)
273 uint32_t stack_ptr = 0;
275 if (!rtos)
276 return -1;
278 if (thread_id == 0)
279 return -2;
281 if (!rtos->rtos_specific_params)
282 return -1;
284 const struct rtkernel_params *param = rtos->rtos_specific_params;
286 /* Read the stack pointer */
287 int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr);
288 if (retval != ERROR_OK) {
289 LOG_ERROR("Error reading stack pointer from rtkernel thread");
290 return retval;
292 LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32,
293 thread_id + rtos->symbols[sym___off_task2stack].address,
294 stack_ptr);
296 /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */
297 stack_ptr += 4;
299 /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */
300 bool cm4_fpu_enabled = false;
301 struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
302 if (is_armv7m(armv7m_target)) {
303 if (armv7m_target->fp_feature != FP_NONE) {
304 /* Found ARM v7m target which includes a FPU */
305 uint32_t cpacr;
307 retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
308 if (retval != ERROR_OK) {
309 LOG_ERROR("Could not read CPACR register to check FPU state");
310 return -1;
313 /* Check if CP10 and CP11 are set to full access. */
314 if (cpacr & 0x00F00000) {
315 /* Found target with enabled FPU */
316 cm4_fpu_enabled = true;
321 if (!cm4_fpu_enabled) {
322 LOG_DEBUG("cm3 stacking");
323 return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
326 /* Read the LR to decide between stacking with or without FPU */
327 uint32_t lr_svc;
328 retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc);
329 if (retval != ERROR_OK) {
330 LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n");
331 return retval;
334 if ((lr_svc & 0x10) == 0) {
335 LOG_DEBUG("cm4f_fpu stacking");
336 return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
339 LOG_DEBUG("cm4f stacking");
340 return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
343 static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
345 *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem));
346 if (!*symbol_list)
347 return ERROR_FAIL;
349 for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) {
350 (*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name;
351 (*symbol_list)[i].optional = rtkernel_symbol_list[i].optional;
354 return ERROR_OK;
357 static bool rtkernel_detect_rtos(struct target *target)
359 return (target->rtos->symbols) &&
360 (target->rtos->symbols[sym___off_os_state2chain].address != 0);
363 static int rtkernel_create(struct target *target)
365 for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) {
366 if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) {
367 target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i];
368 return 0;
372 LOG_ERROR("Could not find target in rt-kernel compatibility list");
373 return -1;
376 const struct rtos_type rtkernel_rtos = {
377 .name = "rtkernel",
379 .detect_rtos = rtkernel_detect_rtos,
380 .create = rtkernel_create,
381 .update_threads = rtkernel_update_threads,
382 .get_thread_reg_list = rtkernel_get_thread_reg_list,
383 .get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup,