76c0bd23b2857722cfd7e1464ba8acfe5d2be16b
[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 = &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 rtos_free_threadlist(rtos);
210
211 param = (const struct embKernel_params *) rtos->rtos_specific_params;
212
213 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
214 (uint8_t *) &rtos->current_thread);
215 if (retval != ERROR_OK) {
216 LOG_ERROR("Error reading current thread in embKernel thread list");
217 return retval;
218 }
219
220 int64_t max_used_priority = 0;
221 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
222 (uint8_t *) &max_used_priority);
223 if (retval != ERROR_OK)
224 return retval;
225
226 int thread_list_size = 0;
227 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
228 param->thread_count_width, (uint8_t *) &thread_list_size);
229
230 if (retval != ERROR_OK) {
231 LOG_ERROR("Could not read embKernel thread count from target");
232 return retval;
233 }
234
235 /* create space for new thread details */
236 rtos->thread_details = (struct thread_detail *) malloc(sizeof(struct thread_detail) * thread_list_size);
237 if (!rtos->thread_details) {
238 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
239 return ERROR_FAIL;
240 }
241
242 int threadIdx = 0;
243 /* Look for ready tasks */
244 for (int pri = 0; pri < max_used_priority; pri++) {
245 /* Get first item in queue */
246 int64_t iterable = 0;
247 retval = target_read_buffer(rtos->target,
248 rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
249 (uint8_t *) &iterable);
250 if (retval != ERROR_OK)
251 return retval;
252 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
253 /* Get info from this iterable item */
254 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
255 if (retval != ERROR_OK)
256 return retval;
257 /* Get next iterable item */
258 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
259 (uint8_t *) &iterable);
260 if (retval != ERROR_OK)
261 return retval;
262 }
263 }
264 /* Look for sleeping tasks */
265 int64_t iterable = 0;
266 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, 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], "Sleeping");
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 suspended tasks */
283 iterable = 0;
284 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].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], "Suspended");
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 rtos->thread_count = 0;
301 rtos->thread_count = threadIdx;
302 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
303 return 0;
304 }
305
306 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
307 {
308 int retval;
309 const struct embKernel_params *param;
310 int64_t stack_ptr = 0;
311
312 *hex_reg_list = NULL;
313 if (rtos == NULL)
314 return -1;
315
316 if (thread_id == 0)
317 return -2;
318
319 if (rtos->rtos_specific_params == NULL)
320 return -1;
321
322 param = (const struct embKernel_params *) rtos->rtos_specific_params;
323
324 /* Read the stack pointer */
325 retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
326 (uint8_t *) &stack_ptr);
327 if (retval != ERROR_OK) {
328 LOG_ERROR("Error reading stack frame from embKernel thread");
329 return retval;
330 }
331
332 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
333 }
334
335 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
336 {
337 unsigned int i;
338 *symbol_list = (symbol_table_elem_t *) malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(embKernel_symbol_list));
339
340 for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
341 (*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
342
343 return 0;
344 }
345

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)