rtos: remove config.h includes from stackings headers
[openocd.git] / src / rtos / rtkernel.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2016-2023 by Andreas Fritiofson *
5 * andreas.fritiofson@gmail.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
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"
22
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() */
37
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;
43 };
44
45 static const struct rtkernel_params rtkernel_params_list[] = {
46 {
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,
51 },
52 {
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,
57 },
58 };
59
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,
70 };
71
72 struct symbols {
73 const char *name;
74 bool optional;
75 };
76
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 }
88 };
89
90 static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size)
91 {
92 void *new_ptr = malloc(new_size);
93
94 if (new_ptr) {
95 memcpy(new_ptr, ptr, MIN(old_size, new_size));
96 free(ptr);
97 }
98
99 return new_ptr;
100 }
101
102 static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task)
103 {
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;
112 }
113 rtos->thread_details = new_thread_details;
114 struct thread_detail *thread = &new_thread_details[rtos->thread_count];
115
116 *thread = (struct thread_detail){ .threadid = task, .exists = true };
117
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;
124 }
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;
130 }
131 tmp_str[sizeof(tmp_str) - 1] = '\0';
132 LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str);
133
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");
138
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;
145 }
146
147 LOG_DEBUG("task state 0x%" PRIx16, state);
148
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");
165 }
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");
182
183 thread->extra_info_str = strdup(state_str);
184
185 rtos->thread_count = new_thread_count;
186 if (task == current_task)
187 rtos->current_thread = task;
188 return ERROR_OK;
189 }
190
191 static int rtkernel_verify_task(struct rtos *rtos, uint32_t task)
192 {
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;
199 }
200 if (magic != rtos->symbols[sym___val_task_magic].address) {
201 LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic);
202 return ERROR_FAIL;
203 }
204 return retval;
205 }
206
207 static int rtkernel_update_threads(struct rtos *rtos)
208 {
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;
213
214 if (!rtos->symbols) {
215 LOG_ERROR("No symbols for rt-kernel");
216 return -3;
217 }
218
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;
227 }
228 LOG_DEBUG("current task is 0x%" PRIx32, current_task);
229
230 retval = rtkernel_verify_task(rtos, current_task);
231 if (retval != ERROR_OK) {
232 LOG_ERROR("Current task is invalid");
233 return retval;
234 }
235
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);
239
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;
246 }
247 LOG_DEBUG("next entry at 0x%" PRIx32, next);
248 if (next == chain) {
249 LOG_DEBUG("end of chain detected");
250 break;
251 }
252 uint32_t task = next - rtos->symbols[sym___off_task2chain].address;
253 LOG_DEBUG("found task at 0x%" PRIx32, task);
254
255 retval = rtkernel_verify_task(rtos, task);
256 if (retval != ERROR_OK) {
257 LOG_ERROR("Invalid task found");
258 return retval;
259 }
260
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;
265 }
266 }
267 return ERROR_OK;
268 }
269
270 static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
271 struct rtos_reg **reg_list, int *num_regs)
272 {
273 uint32_t stack_ptr = 0;
274
275 if (!rtos)
276 return -1;
277
278 if (thread_id == 0)
279 return -2;
280
281 if (!rtos->rtos_specific_params)
282 return -1;
283
284 const struct rtkernel_params *param = rtos->rtos_specific_params;
285
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;
291 }
292 LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32,
293 thread_id + rtos->symbols[sym___off_task2stack].address,
294 stack_ptr);
295
296 /* Adjust stack pointer to ignore non-standard BASEPRI register stacking */
297 stack_ptr += 4;
298
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;
306
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;
311 }
312
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;
317 }
318 }
319 }
320
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);
324 }
325
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;
332 }
333
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);
337 }
338
339 LOG_DEBUG("cm4f stacking");
340 return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
341 }
342
343 static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
344 {
345 *symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem));
346 if (!*symbol_list)
347 return ERROR_FAIL;
348
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;
352 }
353
354 return ERROR_OK;
355 }
356
357 static bool rtkernel_detect_rtos(struct target *target)
358 {
359 return (target->rtos->symbols) &&
360 (target->rtos->symbols[sym___off_os_state2chain].address != 0);
361 }
362
363 static int rtkernel_create(struct target *target)
364 {
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;
369 }
370 }
371
372 LOG_ERROR("Could not find target in rt-kernel compatibility list");
373 return -1;
374 }
375
376 const struct rtos_type rtkernel_rtos = {
377 .name = "rtkernel",
378
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,
384 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)