1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2016-2023 by Andreas Fritiofson *
5 * andreas.fritiofson@gmail.com *
6 ***************************************************************************/
12 #include <helper/time_support.h>
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.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
{
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,
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 },
90 static void *realloc_preserve(void *ptr
, size_t old_size
, size_t new_size
)
92 void *new_ptr
= malloc(new_size
);
95 memcpy(new_ptr
, ptr
, MIN(old_size
, new_size
));
102 static int rtkernel_add_task(struct rtos
*rtos
, uint32_t task
, uint32_t current_task
)
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
);
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 */
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");
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");
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
);
137 thread
->thread_name_str
= strdup("No Name");
139 /* Read the task 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");
147 LOG_DEBUG("task state 0x%" PRIx16
, state
);
149 char state_str
[64] = "";
151 strcat(state_str
, "TT|");
152 if (task
== current_task
) {
153 strcat(state_str
, "RUN");
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");
164 strcat(state_str
, "READY");
167 strcat(state_str
, "|SEM");
169 strcat(state_str
, "|MTX");
171 strcat(state_str
, "|SIG");
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");
179 strcat(state_str
, "|MBOX");
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
;
191 static int rtkernel_verify_task(struct rtos
*rtos
, uint32_t task
)
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");
200 if (magic
!= rtos
->symbols
[sym___val_task_magic
].address
) {
201 LOG_ERROR("Invalid task found (magic=0x%" PRIx32
")", magic
);
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");
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
,
224 if (retval
!= ERROR_OK
) {
225 LOG_ERROR("Error reading current task");
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");
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
;
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");
247 LOG_DEBUG("next entry at 0x%" PRIx32
, next
);
249 LOG_DEBUG("end of chain detected");
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");
261 retval
= rtkernel_add_task(rtos
, task
, current_task
);
262 if (retval
!= ERROR_OK
) {
263 LOG_ERROR("Could not add task to rtos system");
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;
281 if (!rtos
->rtos_specific_params
)
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");
292 LOG_DEBUG("stack pointer at 0x%" PRIx64
", value 0x%" PRIx32
,
293 thread_id
+ rtos
->symbols
[sym___off_task2stack
].address
,
296 /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */
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 */
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");
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 */
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");
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
));
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
;
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
];
372 LOG_ERROR("Could not find target in rt-kernel compatibility list");
376 const struct rtos_type rtkernel_rtos
= {
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
,