rtos: fix print format specifiers
[openocd.git] / src / rtos / mqx.c
1 /***************************************************************************
2 * Copyright (C) 2014 by Marian Cingel *
3 * cingel.marian@gmail.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 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdint.h>
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_mqx_stackings.h"
33
34 /* constants */
35 #define MQX_THREAD_NAME_LENGTH (255)
36 #define MQX_KERNEL_OFFSET_TDLIST (0x0108)
37 #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050)
38 #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C)
39 #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000)
40 #define MQX_QUEUE_OFFSET_SIZE (0x0008)
41 #define MQX_TASK_OFFSET_STATE (0x0008)
42 #define MQX_TASK_OFFSET_ID (0x000c)
43 #define MQX_TASK_OFFSET_TEMPLATE (0x0068)
44 #define MQX_TASK_OFFSET_STACK (0x0014)
45 #define MQX_TASK_OFFSET_TDLIST (0x006C)
46 #define MQX_TASK_OFFSET_NEXT (0x0000)
47 #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010)
48 #define MQX_TASK_OFFSET_ERROR_CODE (0x005C)
49 #define MQX_TASK_STATE_MASK (0xFFF)
50
51 /* types */
52 enum mqx_symbols {
53 mqx_VAL_mqx_kernel_data,
54 mqx_VAL_MQX_init_struct,
55 };
56
57 enum mqx_arch {
58 mqx_arch_cortexm,
59 };
60
61 struct mqx_params {
62 const char *target_name;
63 const enum mqx_arch target_arch;
64 const struct rtos_register_stacking *stacking_info;
65 };
66
67 struct mqx_state {
68 uint32_t state;
69 char *name;
70 };
71
72 /* local data */
73 static const struct mqx_state mqx_states[] = {
74 { 0x0002, "READY" },
75 { 0x0003, "BLOCKED" },
76 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
77 { 0x0007, "RCV_ANY_BLOCKED" },
78 { 0x0009, "DYING" },
79 { 0x000B, "UNHANDLED_INT_BLOCKED" },
80 { 0x000D, "SEND_BLOCKED" },
81 { 0x000F, "BREAKPOINT_BLOCKED" },
82 { 0x0211, "IO_BLOCKED" },
83 { 0x0021, "SEM_BLOCKED" },
84 { 0x0223, "MUTEX_BLOCKED" },
85 { 0x0025, "EVENT_BLOCKED" },
86 { 0x0229, "TASK_QUEUE_BLOCKED" },
87 { 0x042B, "LWSEM_BLOCKED" },
88 { 0x042D, "LWEVENT_BLOCKED" },
89 };
90
91 static const char * const mqx_symbol_list[] = {
92 "_mqx_kernel_data",
93 "MQX_init_struct",
94 NULL
95 };
96
97 static const struct mqx_params mqx_params_list[] = {
98 { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking },
99 };
100
101 /*
102 * Perform simple address check to avoid bus fault.
103 */
104 static int mqx_valid_address_check(
105 struct rtos *rtos,
106 uint32_t address
107 )
108 {
109 enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch;
110 const char * targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name;
111
112 /* Cortex M address range */
113 if (arch_type == mqx_arch_cortexm) {
114 if (
115 /* code and sram area */
116 (address && address <= 0x3FFFFFFFu) ||
117 /* external ram area*/
118 (address >= 0x6000000u && address <= 0x9FFFFFFFu)
119 ) {
120 return ERROR_OK;
121 }
122 return ERROR_FAIL;
123 }
124 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname);
125 return ERROR_FAIL;
126 }
127
128 /*
129 * Wrapper of 'target_read_buffer' fn.
130 * Include address check.
131 */
132 static int mqx_target_read_buffer(
133 struct target *target,
134 uint32_t address,
135 uint32_t size,
136 uint8_t *buffer
137 )
138 {
139 int status = mqx_valid_address_check(target->rtos, address);
140 if (status != ERROR_OK) {
141 LOG_WARNING("MQX RTOS - target address 0x%" PRIx32 " is not allowed to read", address);
142 return status;
143 }
144 status = target_read_buffer(target, address, size, buffer);
145 if (status != ERROR_OK) {
146 LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32" failed", address);
147 return status;
148 }
149 return ERROR_OK;
150 }
151
152 /*
153 * Get symbol address if present
154 */
155 static int mqx_get_symbol(
156 struct rtos *rtos,
157 enum mqx_symbols symbol,
158 void *result
159 )
160 {
161 /* TODO: additional check ?? */
162 (*(int *)result) = (uint32_t)rtos->symbols[symbol].address;
163 return ERROR_OK;
164 }
165
166 /*
167 * Get value of struct member by passing
168 * member offset, width and name (debug purpose)
169 */
170 static int mqx_get_member(
171 struct rtos *rtos,
172 const uint32_t base_address,
173 int32_t member_offset,
174 int32_t member_width,
175 const char *member_name,
176 void *result
177 )
178 {
179 int status = ERROR_FAIL;
180 status = mqx_target_read_buffer(
181 rtos->target, base_address + member_offset, member_width, result
182 );
183 if (status != ERROR_OK)
184 LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32,
185 member_name, (uint32_t)(base_address + member_offset));
186 return status;
187 }
188
189 /*
190 * Check whether scheduler started
191 */
192 static int mqx_is_scheduler_running(
193 struct rtos *rtos
194 )
195 {
196 uint32_t kernel_data_symbol = 0;
197 uint32_t kernel_data_addr = 0;
198 uint32_t system_td_addr = 0;
199 uint32_t active_td_addr = 0;
200 uint32_t capability_value = 0;
201
202 /* get '_mqx_kernel_data' symbol */
203 if (ERROR_OK != mqx_get_symbol(
204 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_symbol
205 )) {
206 return ERROR_FAIL;
207 }
208 /* get '_mqx_kernel_data' */
209 if (ERROR_OK != mqx_get_member(
210 rtos, kernel_data_symbol, 0, 4,
211 "_mqx_kernel_data", &kernel_data_addr
212 )) {
213 return ERROR_FAIL;
214 }
215 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
216 if (0 == kernel_data_addr || (uint32_t)(-1) == kernel_data_addr)
217 return ERROR_FAIL;
218 /* get kernel_data->ADDRESSING_CAPABILITY */
219 if (ERROR_OK != mqx_get_member(
220 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4,
221 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value
222 )) {
223 return ERROR_FAIL;
224 }
225 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
226 it supose to be set to value 8 */
227 if (capability_value != 8) {
228 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
229 return ERROR_FAIL;
230 }
231 /* get active ptr */
232 if (ERROR_OK != mqx_get_member(
233 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
234 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
235 )) {
236 return ERROR_FAIL;
237 }
238 /* active task is system task, scheduler has not not run yet */
239 system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK;
240 if (active_td_addr == system_td_addr) {
241 LOG_WARNING("MQX RTOS - scheduler does not run");
242 return ERROR_FAIL;
243 }
244 return ERROR_OK;
245 }
246
247 /*
248 * API function, return 1 if MQX is present
249 */
250 static int mqx_detect_rtos(
251 struct target *target
252 )
253 {
254 if (
255 (target->rtos->symbols != NULL) &&
256 (target->rtos->symbols[mqx_VAL_mqx_kernel_data].address != 0)
257 ) {
258 return 1;
259 }
260 return 0;
261 }
262
263 /*
264 * API function, pass MQX extra info to context data
265 */
266 static int mqx_create(
267 struct target *target
268 )
269 {
270 /* check target name against supported architectures */
271 int mqx_params_list_num = (sizeof(mqx_params_list)/sizeof(struct mqx_params));
272 for (int i = 0; i < mqx_params_list_num; i++) {
273 if (0 == strcmp(mqx_params_list[i].target_name, target->type->name)) {
274 target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
275 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
276 return 0;
277 }
278 }
279 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
280 return -1;
281 }
282
283 /*
284 * API function, update list of threads
285 */
286 static int mqx_update_threads(
287 struct rtos *rtos
288 )
289 {
290 uint32_t task_queue_addr = 0;
291 uint32_t kernel_data_addr = 0;
292 uint16_t task_queue_size = 0;
293 uint32_t active_td_addr = 0;
294
295 /* clear old data */
296 rtos_free_threadlist(rtos);
297 /* check scheduler */
298 if (ERROR_OK != mqx_is_scheduler_running(rtos))
299 return ERROR_FAIL;
300 /* get kernel_data symbol */
301 if (ERROR_OK != mqx_get_symbol(
302 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
303 )) {
304 return ERROR_FAIL;
305 }
306 /* read kernel_data */
307 if (ERROR_OK != mqx_get_member(
308 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
309 )) {
310 return ERROR_FAIL;
311 }
312 /* get task queue address */
313 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
314 /* get task queue size */
315 if (ERROR_OK != mqx_get_member(
316 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
317 "kernel_data->TD_LIST.SIZE", &task_queue_size
318 )) {
319 return ERROR_FAIL;
320 }
321 /* get active ptr */
322 if (ERROR_OK != mqx_get_member(
323 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
324 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
325 )) {
326 return ERROR_FAIL;
327 }
328
329 /* setup threads info */
330 rtos->thread_count = task_queue_size;
331 rtos->current_thread = 0;
332 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
333 if (NULL == rtos->thread_details)
334 return ERROR_FAIL;
335
336 /* loop over each task and setup thread details,
337 the current_taskpool_addr is set to queue head
338 NOTE: debugging functions task create/destroy
339 might cause to show invalid data.
340 */
341 for (
342 uint32_t i = 0, taskpool_addr = task_queue_addr;
343 i < (uint32_t)rtos->thread_count;
344 i++
345 ) {
346 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
347 uint32_t task_addr = 0, task_template = 0, task_state = 0;
348 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
349 uint32_t state_index = 0, state_max = 0;
350 uint32_t extra_info_length = 0;
351 char *state_name = "unknown state";
352
353 /* set current taskpool address */
354 if (ERROR_OK != mqx_get_member(
355 rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
356 "td_struct_ptr->NEXT", &taskpool_addr
357 )) {
358 return ERROR_FAIL;
359 }
360 /* get task address from taskpool */
361 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
362 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
363 if (ERROR_OK != mqx_get_member(
364 rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
365 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
366 )) {
367 return ERROR_FAIL;
368 }
369 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
370 if (ERROR_OK != mqx_get_member(
371 rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
372 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
373 )) {
374 return ERROR_FAIL;
375 }
376 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
377 if (ERROR_OK != mqx_get_member(
378 rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
379 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
380 )) {
381 return ERROR_FAIL;
382 }
383 /* always terminate last character by force,
384 otherwise openocd might fail if task_name
385 has corrupted data */
386 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
387 /* get value of 'td_struct_ptr->TASK_ID' */
388 if (ERROR_OK != mqx_get_member(
389 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
390 "td_struct_ptr->TASK_ID", &task_id
391 )) {
392 return ERROR_FAIL;
393 }
394 /* get task errno */
395 if (ERROR_OK != mqx_get_member(
396 rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
397 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
398 )) {
399 return ERROR_FAIL;
400 }
401 /* get value of 'td_struct_ptr->STATE' */
402 if (ERROR_OK != mqx_get_member(
403 rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
404 "td_struct_ptr->STATE", &task_state
405 )) {
406 return ERROR_FAIL;
407 }
408 task_state &= MQX_TASK_STATE_MASK;
409 /* and search for defined state */
410 state_max = (sizeof(mqx_states)/sizeof(struct mqx_state));
411 for (state_index = 0; (state_index < state_max); state_index++) {
412 if (mqx_states[state_index].state == task_state) {
413 state_name = mqx_states[state_index].name;
414 break;
415 }
416 }
417
418 /* setup thread details struct */
419 rtos->thread_details[i].threadid = task_id;
420 rtos->thread_details[i].exists = true;
421 rtos->thread_details[i].display_str = NULL;
422 /* set thread name */
423 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
424 if (NULL == rtos->thread_details[i].thread_name_str)
425 return ERROR_FAIL;
426 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
427 /* set thread extra info
428 * - task state
429 * - task address
430 * - task errno
431 * calculate length as:
432 * state length + address length + errno length + formatter length
433 */
434 extra_info_length += strlen((void *)state_name) + 8 + 8 + 8;
435 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
436 if (NULL == rtos->thread_details[i].extra_info_str)
437 return ERROR_FAIL;
438 snprintf(
439 rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32,
440 state_name, task_addr, task_errno
441 );
442 /* set active thread */
443 if (active_td_addr == task_addr)
444 rtos->current_thread = task_id;
445 }
446 return ERROR_OK;
447 }
448
449 /*
450 * API function, get info of selected thread
451 */
452 static int mqx_get_thread_reg_list(
453 struct rtos *rtos,
454 int64_t thread_id,
455 char **hex_reg_list
456 )
457 {
458 int64_t stack_ptr = 0;
459 uint32_t my_task_addr = 0;
460 uint32_t task_queue_addr = 0;
461 uint32_t task_queue_size = 0;
462 uint32_t kernel_data_addr = 0;
463
464 *hex_reg_list = NULL;
465 if (thread_id == 0) {
466 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
467 return ERROR_FAIL;
468 }
469 if (ERROR_OK != mqx_is_scheduler_running(rtos))
470 return ERROR_FAIL;
471 /* get kernel_data symbol */
472 if (ERROR_OK != mqx_get_symbol(
473 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
474 )) {
475 return ERROR_FAIL;
476 }
477 /* read kernel_data */
478 if (ERROR_OK != mqx_get_member(
479 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
480 )) {
481 return ERROR_FAIL;
482 }
483 /* get task queue address */
484 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
485 /* get task queue size */
486 if (ERROR_OK != mqx_get_member(
487 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
488 "kernel_data->TD_LIST.SIZE", &task_queue_size
489 )) {
490 return ERROR_FAIL;
491 }
492 /* search for taskid */
493 for (
494 uint32_t i = 0, taskpool_addr = task_queue_addr;
495 i < (uint32_t)rtos->thread_count;
496 i++
497 ) {
498 uint32_t tmp_address = 0, task_addr = 0;
499 uint32_t task_id = 0;
500 /* set current taskpool address */
501 tmp_address = taskpool_addr;
502 if (ERROR_OK != mqx_get_member(
503 rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
504 "td_struct_ptr->NEXT", &taskpool_addr
505 )) {
506 return ERROR_FAIL;
507 }
508 /* get task address from taskpool */
509 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
510 /* get value of td_struct->TASK_ID */
511 if (ERROR_OK != mqx_get_member(
512 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
513 "td_struct_ptr->TASK_ID", &task_id
514 )) {
515 return ERROR_FAIL;
516 }
517 /* found taskid, break */
518 if (task_id == thread_id) {
519 my_task_addr = task_addr;
520 break;
521 }
522 }
523 if (!my_task_addr) {
524 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
525 return ERROR_FAIL;
526 }
527 /* get task stack head address */
528 if (ERROR_OK != mqx_get_member(
529 rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr
530 )) {
531 return ERROR_FAIL;
532 }
533 return rtos_generic_stack_read(
534 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
535 );
536 }
537
538 /* API function, export list of required symbols */
539 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
540 {
541 *symbol_list = malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(mqx_symbol_list));
542 if (NULL == *symbol_list)
543 return ERROR_FAIL;
544 /* export required symbols */
545 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
546 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
547 return ERROR_OK;
548 }
549
550 struct rtos_type mqx_rtos = {
551 .name = "mqx",
552 .detect_rtos = mqx_detect_rtos,
553 .create = mqx_create,
554 .update_threads = mqx_update_threads,
555 .get_thread_reg_list = mqx_get_thread_reg_list,
556 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
557 };

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)