openocd: fix SPDX tag format for files .c
[openocd.git] / src / rtos / eCos.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 ***************************************************************************/
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <helper/time_support.h>
11 #include <jtag/jtag.h>
12 #include "target/target.h"
13 #include "target/target_type.h"
14 #include "rtos.h"
15 #include "helper/log.h"
16 #include "helper/types.h"
17 #include "rtos_ecos_stackings.h"
18
19 static bool ecos_detect_rtos(struct target *target);
20 static int ecos_create(struct target *target);
21 static int ecos_update_threads(struct rtos *rtos);
22 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
23 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
24
25 struct ecos_thread_state {
26 int value;
27 const char *desc;
28 };
29
30 static const struct ecos_thread_state ecos_thread_states[] = {
31 { 0, "Ready" },
32 { 1, "Sleeping" },
33 { 2, "Countsleep" },
34 { 4, "Suspended" },
35 { 8, "Creating" },
36 { 16, "Exited" }
37 };
38
39 #define ECOS_NUM_STATES ARRAY_SIZE(ecos_thread_states)
40
41 struct ecos_params {
42 const char *target_name;
43 unsigned char pointer_width;
44 unsigned char thread_stack_offset;
45 unsigned char thread_name_offset;
46 unsigned char thread_state_offset;
47 unsigned char thread_next_offset;
48 unsigned char thread_uniqueid_offset;
49 const struct rtos_register_stacking *stacking_info;
50 };
51
52 static const struct ecos_params ecos_params_list[] = {
53 {
54 "cortex_m", /* target_name */
55 4, /* pointer_width; */
56 0x0c, /* thread_stack_offset; */
57 0x9c, /* thread_name_offset; */
58 0x3c, /* thread_state_offset; */
59 0xa0, /* thread_next_offset */
60 0x4c, /* thread_uniqueid_offset */
61 &rtos_ecos_cortex_m3_stacking /* stacking_info */
62 }
63 };
64
65 enum ecos_symbol_values {
66 ECOS_VAL_THREAD_LIST = 0,
67 ECOS_VAL_CURRENT_THREAD_PTR = 1
68 };
69
70 static const char * const ecos_symbol_list[] = {
71 "Cyg_Thread::thread_list",
72 "Cyg_Scheduler_Base::current_thread",
73 NULL
74 };
75
76 const struct rtos_type ecos_rtos = {
77 .name = "eCos",
78
79 .detect_rtos = ecos_detect_rtos,
80 .create = ecos_create,
81 .update_threads = ecos_update_threads,
82 .get_thread_reg_list = ecos_get_thread_reg_list,
83 .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup,
84
85 };
86
87 static int ecos_update_threads(struct rtos *rtos)
88 {
89 int retval;
90 int tasks_found = 0;
91 int thread_list_size = 0;
92 const struct ecos_params *param;
93
94 if (!rtos)
95 return -1;
96
97 if (!rtos->rtos_specific_params)
98 return -3;
99
100 param = (const struct ecos_params *) rtos->rtos_specific_params;
101
102 if (!rtos->symbols) {
103 LOG_ERROR("No symbols for eCos");
104 return -4;
105 }
106
107 if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) {
108 LOG_ERROR("Don't have the thread list head");
109 return -2;
110 }
111
112 /* wipe out previous thread details if any */
113 rtos_free_threadlist(rtos);
114
115 /* determine the number of current threads */
116 uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
117 uint32_t thread_index;
118 target_read_buffer(rtos->target,
119 thread_list_head,
120 param->pointer_width,
121 (uint8_t *) &thread_index);
122 uint32_t first_thread = thread_index;
123 do {
124 thread_list_size++;
125 retval = target_read_buffer(rtos->target,
126 thread_index + param->thread_next_offset,
127 param->pointer_width,
128 (uint8_t *) &thread_index);
129 if (retval != ERROR_OK)
130 return retval;
131 } while (thread_index != first_thread);
132
133 /* read the current thread id */
134 uint32_t current_thread_addr;
135 retval = target_read_buffer(rtos->target,
136 rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address,
137 4,
138 (uint8_t *)&current_thread_addr);
139 if (retval != ERROR_OK)
140 return retval;
141 rtos->current_thread = 0;
142 retval = target_read_buffer(rtos->target,
143 current_thread_addr + param->thread_uniqueid_offset,
144 2,
145 (uint8_t *)&rtos->current_thread);
146 if (retval != ERROR_OK) {
147 LOG_ERROR("Could not read eCos current thread from target");
148 return retval;
149 }
150
151 if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
152 /* Either : No RTOS threads - there is always at least the current execution though */
153 /* OR : No current thread - all threads suspended - show the current execution
154 * of idling */
155 char tmp_str[] = "Current Execution";
156 thread_list_size++;
157 tasks_found++;
158 rtos->thread_details = malloc(
159 sizeof(struct thread_detail) * thread_list_size);
160 rtos->thread_details->threadid = 1;
161 rtos->thread_details->exists = true;
162 rtos->thread_details->extra_info_str = NULL;
163 rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
164 strcpy(rtos->thread_details->thread_name_str, tmp_str);
165
166 if (thread_list_size == 0) {
167 rtos->thread_count = 1;
168 return ERROR_OK;
169 }
170 } else {
171 /* create space for new thread details */
172 rtos->thread_details = malloc(
173 sizeof(struct thread_detail) * thread_list_size);
174 }
175
176 /* loop over all threads */
177 thread_index = first_thread;
178 do {
179
180 #define ECOS_THREAD_NAME_STR_SIZE (200)
181 char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
182 unsigned int i = 0;
183 uint32_t name_ptr = 0;
184 uint32_t prev_thread_ptr;
185
186 /* Save the thread pointer */
187 uint16_t thread_id;
188 retval = target_read_buffer(rtos->target,
189 thread_index + param->thread_uniqueid_offset,
190 2,
191 (uint8_t *)&thread_id);
192 if (retval != ERROR_OK) {
193 LOG_ERROR("Could not read eCos thread id from target");
194 return retval;
195 }
196 rtos->thread_details[tasks_found].threadid = thread_id;
197
198 /* read the name pointer */
199 retval = target_read_buffer(rtos->target,
200 thread_index + param->thread_name_offset,
201 param->pointer_width,
202 (uint8_t *)&name_ptr);
203 if (retval != ERROR_OK) {
204 LOG_ERROR("Could not read eCos thread name pointer from target");
205 return retval;
206 }
207
208 /* Read the thread name */
209 retval =
210 target_read_buffer(rtos->target,
211 name_ptr,
212 ECOS_THREAD_NAME_STR_SIZE,
213 (uint8_t *)&tmp_str);
214 if (retval != ERROR_OK) {
215 LOG_ERROR("Error reading thread name from eCos target");
216 return retval;
217 }
218 tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
219
220 if (tmp_str[0] == '\x00')
221 strcpy(tmp_str, "No Name");
222
223 rtos->thread_details[tasks_found].thread_name_str =
224 malloc(strlen(tmp_str)+1);
225 strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
226
227 /* Read the thread status */
228 int64_t thread_status = 0;
229 retval = target_read_buffer(rtos->target,
230 thread_index + param->thread_state_offset,
231 4,
232 (uint8_t *)&thread_status);
233 if (retval != ERROR_OK) {
234 LOG_ERROR("Error reading thread state from eCos target");
235 return retval;
236 }
237
238 for (i = 0; (i < ECOS_NUM_STATES) && (ecos_thread_states[i].value != thread_status); i++) {
239 /*
240 * empty
241 */
242 }
243
244 const char *state_desc;
245 if (i < ECOS_NUM_STATES)
246 state_desc = ecos_thread_states[i].desc;
247 else
248 state_desc = "Unknown state";
249
250 rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
251 state_desc)+8);
252 sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
253
254 rtos->thread_details[tasks_found].exists = true;
255
256 tasks_found++;
257 prev_thread_ptr = thread_index;
258
259 /* Get the location of the next thread structure. */
260 thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
261 retval = target_read_buffer(rtos->target,
262 prev_thread_ptr + param->thread_next_offset,
263 param->pointer_width,
264 (uint8_t *) &thread_index);
265 if (retval != ERROR_OK) {
266 LOG_ERROR("Error reading next thread pointer in eCos thread list");
267 return retval;
268 }
269 } while (thread_index != first_thread);
270
271 rtos->thread_count = tasks_found;
272 return 0;
273 }
274
275 static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
276 struct rtos_reg **reg_list, int *num_regs)
277 {
278 int retval;
279 const struct ecos_params *param;
280
281 if (!rtos)
282 return -1;
283
284 if (thread_id == 0)
285 return -2;
286
287 if (!rtos->rtos_specific_params)
288 return -3;
289
290 param = (const struct ecos_params *) rtos->rtos_specific_params;
291
292 /* Find the thread with that thread id */
293 uint16_t id = 0;
294 uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
295 uint32_t thread_index;
296 target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
297 (uint8_t *)&thread_index);
298 bool done = false;
299 while (!done) {
300 retval = target_read_buffer(rtos->target,
301 thread_index + param->thread_uniqueid_offset,
302 2,
303 (uint8_t *)&id);
304 if (retval != ERROR_OK) {
305 LOG_ERROR("Error reading unique id from eCos thread");
306 return retval;
307 }
308
309 if (id == thread_id) {
310 done = true;
311 break;
312 }
313 target_read_buffer(rtos->target,
314 thread_index + param->thread_next_offset,
315 param->pointer_width,
316 (uint8_t *) &thread_index);
317 }
318
319 if (done) {
320 /* Read the stack pointer */
321 int64_t stack_ptr = 0;
322 retval = target_read_buffer(rtos->target,
323 thread_index + param->thread_stack_offset,
324 param->pointer_width,
325 (uint8_t *)&stack_ptr);
326 if (retval != ERROR_OK) {
327 LOG_ERROR("Error reading stack frame from eCos thread");
328 return retval;
329 }
330
331 return rtos_generic_stack_read(rtos->target,
332 param->stacking_info,
333 stack_ptr,
334 reg_list,
335 num_regs);
336 }
337
338 return -1;
339 }
340
341 static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
342 {
343 unsigned int i;
344 *symbol_list = calloc(
345 ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem));
346
347 for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++)
348 (*symbol_list)[i].symbol_name = ecos_symbol_list[i];
349
350 return 0;
351 }
352
353 static bool ecos_detect_rtos(struct target *target)
354 {
355 if ((target->rtos->symbols) &&
356 (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) {
357 /* looks like eCos */
358 return true;
359 }
360 return false;
361 }
362
363 static int ecos_create(struct target *target)
364 {
365 for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++)
366 if (strcmp(ecos_params_list[i].target_name, target->type->name) == 0) {
367 target->rtos->rtos_specific_params = (void *)&ecos_params_list[i];
368 target->rtos->current_thread = 0;
369 target->rtos->thread_details = NULL;
370 return 0;
371 }
372
373 LOG_ERROR("Could not find target in eCos compatibility list");
374 return -1;
375 }

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)