rtos: Use 'bool' as return type for detect_rtos()
[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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/time_support.h>
24 #include <jtag/jtag.h>
25 #include "target/target.h"
26 #include "target/target_type.h"
27 #include "rtos.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos_embkernel_stackings.h"
31
32 #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64)
33
34 static bool embKernel_detect_rtos(struct target *target);
35 static int embKernel_create(struct target *target);
36 static int embKernel_update_threads(struct rtos *rtos);
37 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
38 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
39
40 struct rtos_type embKernel_rtos = {
41 .name = "embKernel",
42 .detect_rtos = embKernel_detect_rtos,
43 .create = embKernel_create,
44 .update_threads = embKernel_update_threads,
45 .get_thread_reg_list =
46 embKernel_get_thread_reg_list,
47 .get_symbol_list_to_lookup = embKernel_get_symbol_list_to_lookup,
48 };
49
50 enum {
51 SYMBOL_ID_sCurrentTask = 0,
52 SYMBOL_ID_sListReady = 1,
53 SYMBOL_ID_sListSleep = 2,
54 SYMBOL_ID_sListSuspended = 3,
55 SYMBOL_ID_sMaxPriorities = 4,
56 SYMBOL_ID_sCurrentTaskCount = 5,
57 };
58
59 static const char * const embKernel_symbol_list[] = {
60 "Rtos::sCurrentTask",
61 "Rtos::sListReady",
62 "Rtos::sListSleep",
63 "Rtos::sListSuspended",
64 "Rtos::sMaxPriorities",
65 "Rtos::sCurrentTaskCount",
66 NULL };
67
68 struct embKernel_params {
69 const char *target_name;
70 const unsigned char pointer_width;
71 const unsigned char thread_count_width;
72 const unsigned char rtos_list_size;
73 const unsigned char thread_stack_offset;
74 const unsigned char thread_name_offset;
75 const unsigned char thread_priority_offset;
76 const unsigned char thread_priority_width;
77 const unsigned char iterable_next_offset;
78 const unsigned char iterable_task_owner_offset;
79 const struct rtos_register_stacking *stacking_info;
80 };
81
82 static const struct embKernel_params embKernel_params_list[] = {
83 {
84 "cortex_m", /* target_name */
85 4, /* pointer_width */
86 4, /* thread_count_width */
87 8, /*rtos_list_size */
88 0, /*thread_stack_offset */
89 4, /*thread_name_offset */
90 8, /*thread_priority_offset */
91 4, /*thread_priority_width */
92 4, /*iterable_next_offset */
93 12, /*iterable_task_owner_offset */
94 &rtos_embkernel_Cortex_M_stacking, /* stacking_info*/
95 },
96 { "hla_target", /* target_name */
97 4, /* pointer_width */
98 4, /* thread_count_width */
99 8, /*rtos_list_size */
100 0, /*thread_stack_offset */
101 4, /*thread_name_offset */
102 8, /*thread_priority_offset */
103 4, /*thread_priority_width */
104 4, /*iterable_next_offset */
105 12, /*iterable_task_owner_offset */
106 &rtos_embkernel_Cortex_M_stacking, /* stacking_info */
107 }
108 };
109
110 static bool embKernel_detect_rtos(struct target *target)
111 {
112 if (target->rtos->symbols != NULL) {
113 if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0)
114 return true;
115 }
116 return false;
117 }
118
119 static int embKernel_create(struct target *target)
120 {
121 size_t i = 0;
122 while ((i < ARRAY_SIZE(embKernel_params_list)) &&
123 (0 != strcmp(embKernel_params_list[i].target_name, target->type->name)))
124 i++;
125
126 if (i >= ARRAY_SIZE(embKernel_params_list)) {
127 LOG_WARNING("Could not find target \"%s\" in embKernel compatibility "
128 "list", target->type->name);
129 return -1;
130 }
131
132 target->rtos->rtos_specific_params = (void *) &embKernel_params_list[i];
133 return 0;
134 }
135
136 static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
137 struct thread_detail *details, const char* state_str)
138 {
139 int64_t task = 0;
140 int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
141 (uint8_t *) &task);
142 if (retval != ERROR_OK)
143 return retval;
144 details->threadid = (threadid_t) task;
145 details->exists = true;
146
147 int64_t name_ptr = 0;
148 retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
149 (uint8_t *) &name_ptr);
150 if (retval != ERROR_OK)
151 return retval;
152
153 details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
154 if (name_ptr) {
155 retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
156 (uint8_t *) details->thread_name_str);
157 if (retval != ERROR_OK)
158 return retval;
159 details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
160 } else {
161 snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
162 }
163
164 int64_t priority = 0;
165 retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
166 (uint8_t *) &priority);
167 if (retval != ERROR_OK)
168 return retval;
169 details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
170 if (task == rtos->current_thread) {
171 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: Running, Priority: %u",
172 (unsigned int) priority);
173 } else {
174 snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "State: %s, Priority: %u",
175 state_str, (unsigned int) priority);
176 }
177
178 LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
179 (unsigned int)task, details->thread_name_str);
180 return 0;
181 }
182
183 static int embKernel_update_threads(struct rtos *rtos)
184 {
185 /* int i = 0; */
186 int retval;
187 const struct embKernel_params *param;
188
189 if (rtos == NULL)
190 return -1;
191
192 if (rtos->rtos_specific_params == NULL)
193 return -3;
194
195 if (rtos->symbols == NULL) {
196 LOG_ERROR("No symbols for embKernel");
197 return -4;
198 }
199
200 if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) {
201 LOG_ERROR("Don't have the thread list head");
202 return -2;
203 }
204
205 /* wipe out previous thread details if any */
206 rtos_free_threadlist(rtos);
207
208 param = (const struct embKernel_params *) rtos->rtos_specific_params;
209
210 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
211 (uint8_t *) &rtos->current_thread);
212 if (retval != ERROR_OK) {
213 LOG_ERROR("Error reading current thread in embKernel thread list");
214 return retval;
215 }
216
217 int64_t max_used_priority = 0;
218 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
219 (uint8_t *) &max_used_priority);
220 if (retval != ERROR_OK)
221 return retval;
222
223 int thread_list_size = 0;
224 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
225 param->thread_count_width, (uint8_t *) &thread_list_size);
226
227 if (retval != ERROR_OK) {
228 LOG_ERROR("Could not read embKernel thread count from target");
229 return retval;
230 }
231
232 /* create space for new thread details */
233 rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
234 if (!rtos->thread_details) {
235 LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
236 return ERROR_FAIL;
237 }
238
239 int threadIdx = 0;
240 /* Look for ready tasks */
241 for (int pri = 0; pri < max_used_priority; pri++) {
242 /* Get first item in queue */
243 int64_t iterable = 0;
244 retval = target_read_buffer(rtos->target,
245 rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
246 (uint8_t *) &iterable);
247 if (retval != ERROR_OK)
248 return retval;
249 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
250 /* Get info from this iterable item */
251 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
252 if (retval != ERROR_OK)
253 return retval;
254 /* Get next iterable item */
255 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
256 (uint8_t *) &iterable);
257 if (retval != ERROR_OK)
258 return retval;
259 }
260 }
261 /* Look for sleeping tasks */
262 int64_t iterable = 0;
263 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width,
264 (uint8_t *) &iterable);
265 if (retval != ERROR_OK)
266 return retval;
267 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
268 /*Get info from this iterable item */
269 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping");
270 if (retval != ERROR_OK)
271 return retval;
272 /*Get next iterable item */
273 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
274 (uint8_t *) &iterable);
275 if (retval != ERROR_OK)
276 return retval;
277 }
278
279 /* Look for suspended tasks */
280 iterable = 0;
281 retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width,
282 (uint8_t *) &iterable);
283 if (retval != ERROR_OK)
284 return retval;
285 for (; iterable && threadIdx < thread_list_size; threadIdx++) {
286 /* Get info from this iterable item */
287 retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended");
288 if (retval != ERROR_OK)
289 return retval;
290 /*Get next iterable item */
291 retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
292 (uint8_t *) &iterable);
293 if (retval != ERROR_OK)
294 return retval;
295 }
296
297 rtos->thread_count = 0;
298 rtos->thread_count = threadIdx;
299 LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
300 return 0;
301 }
302
303 static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
304 {
305 int retval;
306 const struct embKernel_params *param;
307 int64_t stack_ptr = 0;
308
309 *hex_reg_list = NULL;
310 if (rtos == NULL)
311 return -1;
312
313 if (thread_id == 0)
314 return -2;
315
316 if (rtos->rtos_specific_params == NULL)
317 return -1;
318
319 param = (const struct embKernel_params *) rtos->rtos_specific_params;
320
321 /* Read the stack pointer */
322 retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width,
323 (uint8_t *) &stack_ptr);
324 if (retval != ERROR_OK) {
325 LOG_ERROR("Error reading stack frame from embKernel thread");
326 return retval;
327 }
328
329 return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
330 }
331
332 static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
333 {
334 unsigned int i;
335 *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(symbol_table_elem_t));
336
337 for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
338 (*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
339
340 return 0;
341 }
342

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)