cortex_m: target implementation renames cortex_m3 to cortex_m
[openocd.git] / src / rtos / embKernel.c
1 /***************************************************************************
2 * Copyright (C) 2011 by Broadcom Corporation *
3 * Evan Hunter - ehunter@broadcom.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
29 #include "rtos.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_embkernel_stackings.h"
33
34 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
35
36 static int embKernel_detect_rtos(struct target *target);
37 static int embKernel_create(struct target *target);
38 static int embKernel_update_threads(struct rtos *rtos);
39 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
40 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
41
42 struct rtos_type embKernel_rtos = {
43 .name = "embKernel",
44 .detect_rtos = embKernel_detect_rtos,
45 .create = embKernel_create,
46 .update_threads = embKernel_update_threads,
47 .get_thread_reg_list =
48 embKernel_get_thread_reg_list,
49 .get_symbol_list_to_lookup = embKernel_get_symbol_list_to_lookup,
50 };
51
52 enum {
53 SYMBOL_ID_sCurrentTask = 0,
54 SYMBOL_ID_sListReady = 1,
55 SYMBOL_ID_sListSleep = 2,
56 SYMBOL_ID_sListSuspended = 3,
57 SYMBOL_ID_sMaxPriorities = 4,
58 SYMBOL_ID_sCurrentTaskCount = 5,
59 };
60
61 static char *embKernel_symbol_list[] = {
62 "Rtos::sCurrentTask",
63 "Rtos::sListReady",
64 "Rtos::sListSleep",
65 "Rtos::sListSuspended",
66 "Rtos::sMaxPriorities",
67 "Rtos::sCurrentTaskCount",
68 NULL };
69
70 struct embKernel_params {
71 const char *target_name;
72 const unsigned char pointer_width;
73 const unsigned char thread_count_width;
74 const unsigned char rtos_list_size;
75 const unsigned char thread_stack_offset;
76 const unsigned char thread_name_offset;
77 const unsigned char thread_priority_offset;
78 const unsigned char thread_priority_width;
79 const unsigned char iterable_next_offset;
80 const unsigned char iterable_task_owner_offset;
81 const struct rtos_register_stacking *stacking_info;
82 };
83
84 struct embKernel_params embKernel_params_list[] = {
85 {
86 "cortex_m", /* target_name */
87 4, /* pointer_width */
88 4, /* thread_count_width */
89 8, /*rtos_list_size */
90 0, /*thread_stack_offset */
91 4, /*thread_name_offset */
92 8, /*thread_priority_offset */
93 4, /*thread_priority_width */
94 4, /*iterable_next_offset */
95 12, /*iterable_task_owner_offset */
96 &rtos_embkernel_Cortex_M_stacking, /* stacking_info*/
97 },
98 { "hla_target", /* target_name */
99 4, /* pointer_width */
100 4, /* thread_count_width */
101 8, /*rtos_list_size */
102 0, /*thread_stack_offset */
103 4, /*thread_name_offset */
104 8, /*thread_priority_offset */
105 4, /*thread_priority_width */
106 4, /*iterable_next_offset */
107 12, /*iterable_task_owner_offset */
108 &rtos_embkernel_Cortex_M_stacking, /* stacking_info */
109 }
110 };
111
112 static int embKernel_detect_rtos(struct target *target)
113 {
114 if (target->rtos->symbols != NULL) {
115 if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0)
116 return 1;
117 }
118 return 0;
119 }
120
121 static int embKernel_create(struct target *target)
122 {
123 size_t i = 0;
124 while ((i < ARRAY_SIZE(embKernel_params_list)) &&
125 (0 != strcmp(embKernel_params_list[i].target_name, target->type->name)))
126 i++;
127
128 if (i >= ARRAY_SIZE(embKernel_params_list)) {
129 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
130 "list", target->type->name);
131 return -1;
132 }
133
134 target->rtos->rtos_specific_params = (void *) &embKernel_params_list[i];
135 return 0;
136 }
137
138 static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
139 struct thread_detail *details, const char* state_str)
140 {
141 int64_t task = 0;
142 int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
143 (uint8_t *) &task);
144 if (retval != ERROR_OK)
145 return retval;
146 details->threadid = (threadid_t) task;
147 details->exists = true;
148 details->display_str = NULL;
149
150 int64_t name_ptr = 0;
151 retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
152 (uint8_t *) &name_ptr);
153 if (retval != ERROR_OK)
154 return retval;
155
156 details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
157 if (name_ptr) {
158 retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
159 (uint8_t *) details->thread_name_str);
160 if (retval != ERROR_OK)
161 return retval;
162 details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
163 } else {
164 snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
165 }
166
167 int64_t priority = 0;
168 retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
169 (uint8_t *) &priority);
170 if (retval != ERROR_OK)
171 return retval;
172 details->extra_info_str = (char *) malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
173 if (task == rtos->current_thread) {
174 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running",
175 (unsigned int) priority);
176 } else {
177 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority,
178 state_str);
179 }
180
181 LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
182 (unsigned int)task, details->thread_name_str);
183 return 0;
184 }
185
186 static int embKernel_update_threads(struct rtos *rtos)
187 {
188 /* int i = 0; */
189 int retval;
190 const struct embKernel_params *param;
191
192 if (rtos == NULL)
193 return -1;
194
195 if (rtos->rtos_specific_params == NULL)
196 return -3;
197
198 if (rtos->symbols == NULL) {
199 LOG_ERROR("No symbols for embKernel");
200 return -4;
201 }
202
203 if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) {
204 LOG_ERROR("Don't have the thread list head");
205 return -2;
206 }
207
208 /* wipe out previous thread details if any */
209 if (rtos->thread_details != NULL) {
210 int j;
211 for (j = 0; j < rtos->thread_count; j++) {
212 if (rtos->thread_details[j].display_str != NULL) {
213 free(rtos->thread_details[j].display_str);
214 rtos->thread_details[j].display_str = NULL;
215 }
216 if (rtos->thread_details[j].thread_name_str != NULL) {
217 free(rtos->thread_details[j].thread_name_str);
218 rtos->thread_details[j].thread_name_str = NULL;
219 }
220 if (rtos->thread_details[j].extra_info_str != NULL) {
221 free(rtos->thread_details[j].extra_info_str);
222 rtos->thread_details[j].extra_info_str = NULL;
223 }
224 }
225 free(rtos->thread_details);
226 rtos->thread_details = NULL;
227 }
228
229 param = (const struct embKernel_params *) rtos->rtos_specific_params;
230
231 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
232 (uint8_t *) &rtos->current_thread);
233 if (retval != ERROR_OK) {
234 LOG_ERROR("Error reading current thread in embKernel thread list");
235 return retval;
236 }
237
238 int64_t max_used_priority = 0;
239 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
240 (uint8_t *) &max_used_priority);
241 if (retval != ERROR_OK)
242 return retval;
243
244 int thread_list_size = 0;
245 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
246 param->thread_count_width, (uint8_t *) &thread_list_size);
247
248 if (retval != ERROR_OK) {
249 LOG_ERROR("Could not read embKernel thread count from target");
250 return retval;
251 }
252
253 /* create space for new thread details */
254 rtos->thread_details = (struct thread_detail *) malloc(sizeof(struct thread_detail) * thread_list_size);
255 if (!rtos->thread_details) {
256 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
257 return ERROR_FAIL;
258 }
259
260 int threadIdx = 0;
261 /* Look for ready tasks */
262 for (int pri = 0; pri < max_used_priority; pri++) {
263 /* Get first item in queue */
264 int64_t iterable = 0;
265 retval = target_read_buffer(rtos->target,
266 rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
267 (uint8_t *) &iterable);
268 if (retval != ERROR_OK)
269 return retval;
270 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
271 /* Get info from this iterable item */
272 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
273 if (retval != ERROR_OK)
274 return retval;
275 /* Get next iterable item */
276 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
277 (uint8_t *) &iterable);
278 if (retval != ERROR_OK)
279 return retval;
280 }
281 }
282 /* Look for sleeping tasks */
283 int64_t iterable = 0;
284 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width,
285 (uint8_t *) &iterable);
286 if (retval != ERROR_OK)
287 return retval;
288 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
289 /*Get info from this iterable item */
290 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping");
291 if (retval != ERROR_OK)
292 return retval;
293 /*Get next iterable item */
294 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
295 (uint8_t *) &iterable);
296 if (retval != ERROR_OK)
297 return retval;
298 }
299
300 /* Look for suspended tasks */
301 iterable = 0;
302 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width,
303 (uint8_t *) &iterable);
304 if (retval != ERROR_OK)
305 return retval;
306 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
307 /* Get info from this iterable item */
308 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended");
309 if (retval != ERROR_OK)
310 return retval;
311 /*Get next iterable item */
312 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
313 (uint8_t *) &iterable);
314 if (retval != ERROR_OK)
315 return retval;
316 }
317
318 rtos->thread_count = 0;
319 rtos->thread_count = threadIdx;
320 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
321 return 0;
322 }
323
324 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
325 {
326 int retval;
327 const struct embKernel_params *param;
328 int64_t stack_ptr = 0;
329
330 *hex_reg_list = NULL;
331 if (rtos == NULL)
332 return -1;
333
334 if (thread_id == 0)
335 return -2;
336
337 if (rtos->rtos_specific_params == NULL)
338 return -1;
339
340 param = (const struct embKernel_params *) rtos->rtos_specific_params;
341
342 /* Read the stack pointer */
343 retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
344 (uint8_t *) &stack_ptr);
345 if (retval != ERROR_OK) {
346 LOG_ERROR("Error reading stack frame from embKernel thread");
347 return retval;
348 }
349
350 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
351 }
352
353 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
354 {
355 unsigned int i;
356 *symbol_list = (symbol_table_elem_t *) malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(embKernel_symbol_list));
357
358 for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
359 (*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
360
361 return 0;
362 }
363

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)