1 /***************************************************************************
2 * Copyright (C) 2014 by Marian Cingel *
3 * cingel.marian@gmail.com *
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. *
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. *
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 ***************************************************************************/
25 #include <helper/time_support.h>
26 #include <jtag/jtag.h>
27 #include "target/target.h"
28 #include "target/target_type.h"
30 #include "helper/log.h"
31 #include "helper/types.h"
32 #include "rtos_mqx_stackings.h"
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)
53 mqx_VAL_mqx_kernel_data
,
54 mqx_VAL_MQX_init_struct
,
62 const char *target_name
;
63 const enum mqx_arch target_arch
;
64 const struct rtos_register_stacking
*stacking_info
;
73 static const struct mqx_state mqx_states
[] = {
75 { 0x0003, "BLOCKED" },
76 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
77 { 0x0007, "RCV_ANY_BLOCKED" },
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" },
91 static const char * const mqx_symbol_list
[] = {
97 static const struct mqx_params mqx_params_list
[] = {
98 { "cortex_m", mqx_arch_cortexm
, &rtos_mqx_arm_v7m_stacking
},
102 * Perform simple address check to avoid bus fault.
104 static int mqx_valid_address_check(
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
;
112 /* Cortex-M address range */
113 if (arch_type
== mqx_arch_cortexm
) {
115 /* code and sram area */
116 (address
&& address
<= 0x3FFFFFFFu
) ||
117 /* external ram area*/
118 (address
>= 0x6000000u
&& address
<= 0x9FFFFFFFu
)
124 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname
);
129 * Wrapper of 'target_read_buffer' fn.
130 * Include address check.
132 static int mqx_target_read_buffer(
133 struct target
*target
,
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
);
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
);
153 * Get symbol address if present
155 static int mqx_get_symbol(
157 enum mqx_symbols symbol
,
161 /* TODO: additional check ?? */
162 (*(int *)result
) = (uint32_t)rtos
->symbols
[symbol
].address
;
167 * Get value of struct member by passing
168 * member offset, width and name (debug purpose)
170 static int mqx_get_member(
172 const uint32_t base_address
,
173 int32_t member_offset
,
174 int32_t member_width
,
175 const char *member_name
,
179 int status
= ERROR_FAIL
;
180 status
= mqx_target_read_buffer(
181 rtos
->target
, base_address
+ member_offset
, member_width
, result
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
));
190 * Check whether scheduler started
192 static int mqx_is_scheduler_running(
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;
202 /* get '_mqx_kernel_data' symbol */
203 if (ERROR_OK
!= mqx_get_symbol(
204 rtos
, mqx_VAL_mqx_kernel_data
, &kernel_data_symbol
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
215 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
216 if (0 == kernel_data_addr
|| (uint32_t)(-1) == kernel_data_addr
)
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
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");
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
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");
248 * API function, return 1 if MQX is present
250 static int mqx_detect_rtos(
251 struct target
*target
255 (target
->rtos
->symbols
!= NULL
) &&
256 (target
->rtos
->symbols
[mqx_VAL_mqx_kernel_data
].address
!= 0)
264 * API function, pass MQX extra info to context data
266 static int mqx_create(
267 struct target
*target
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); */
279 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target
->type
->name
);
284 * API function, update list of threads
286 static int mqx_update_threads(
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;
295 if (!rtos
->rtos_specific_params
)
302 rtos_free_threadlist(rtos
);
303 /* check scheduler */
304 if (ERROR_OK
!= mqx_is_scheduler_running(rtos
))
306 /* get kernel_data symbol */
307 if (ERROR_OK
!= mqx_get_symbol(
308 rtos
, mqx_VAL_mqx_kernel_data
, &kernel_data_addr
312 /* read kernel_data */
313 if (ERROR_OK
!= mqx_get_member(
314 rtos
, kernel_data_addr
, 0, 4, "_mqx_kernel_data", &kernel_data_addr
318 /* get task queue address */
319 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
320 /* get task queue size */
321 if (ERROR_OK
!= mqx_get_member(
322 rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
323 "kernel_data->TD_LIST.SIZE", &task_queue_size
328 if (ERROR_OK
!= mqx_get_member(
329 rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_ACTIVE_TASK
, 4,
330 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
335 /* setup threads info */
336 rtos
->thread_count
= task_queue_size
;
337 rtos
->current_thread
= 0;
338 rtos
->thread_details
= calloc(rtos
->thread_count
, sizeof(struct thread_detail
));
339 if (NULL
== rtos
->thread_details
)
342 /* loop over each task and setup thread details,
343 the current_taskpool_addr is set to queue head
344 NOTE: debugging functions task create/destroy
345 might cause to show invalid data.
348 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
349 i
< (uint32_t)rtos
->thread_count
;
352 uint8_t task_name
[MQX_THREAD_NAME_LENGTH
+ 1];
353 uint32_t task_addr
= 0, task_template
= 0, task_state
= 0;
354 uint32_t task_name_addr
= 0, task_id
= 0, task_errno
= 0;
355 uint32_t state_index
= 0, state_max
= 0;
356 uint32_t extra_info_length
= 0;
357 char *state_name
= "unknown state";
359 /* set current taskpool address */
360 if (ERROR_OK
!= mqx_get_member(
361 rtos
, taskpool_addr
, MQX_TASK_OFFSET_NEXT
, 4,
362 "td_struct_ptr->NEXT", &taskpool_addr
366 /* get task address from taskpool */
367 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
368 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
369 if (ERROR_OK
!= mqx_get_member(
370 rtos
, task_addr
, MQX_TASK_OFFSET_TEMPLATE
, 4,
371 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
375 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
376 if (ERROR_OK
!= mqx_get_member(
377 rtos
, task_template
, MQX_TASK_TEMPLATE_OFFSET_NAME
, 4,
378 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
382 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
383 if (ERROR_OK
!= mqx_get_member(
384 rtos
, task_name_addr
, 0, MQX_THREAD_NAME_LENGTH
,
385 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
389 /* always terminate last character by force,
390 otherwise openocd might fail if task_name
391 has corrupted data */
392 task_name
[MQX_THREAD_NAME_LENGTH
] = '\0';
393 /* get value of 'td_struct_ptr->TASK_ID' */
394 if (ERROR_OK
!= mqx_get_member(
395 rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
396 "td_struct_ptr->TASK_ID", &task_id
401 if (ERROR_OK
!= mqx_get_member(
402 rtos
, task_addr
, MQX_TASK_OFFSET_ERROR_CODE
, 4,
403 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
407 /* get value of 'td_struct_ptr->STATE' */
408 if (ERROR_OK
!= mqx_get_member(
409 rtos
, task_addr
, MQX_TASK_OFFSET_STATE
, 4,
410 "td_struct_ptr->STATE", &task_state
414 task_state
&= MQX_TASK_STATE_MASK
;
415 /* and search for defined state */
416 state_max
= (sizeof(mqx_states
)/sizeof(struct mqx_state
));
417 for (state_index
= 0; (state_index
< state_max
); state_index
++) {
418 if (mqx_states
[state_index
].state
== task_state
) {
419 state_name
= mqx_states
[state_index
].name
;
424 /* setup thread details struct */
425 rtos
->thread_details
[i
].threadid
= task_id
;
426 rtos
->thread_details
[i
].exists
= true;
427 rtos
->thread_details
[i
].display_str
= NULL
;
428 /* set thread name */
429 rtos
->thread_details
[i
].thread_name_str
= malloc(strlen((void *)task_name
) + 1);
430 if (NULL
== rtos
->thread_details
[i
].thread_name_str
)
432 strcpy(rtos
->thread_details
[i
].thread_name_str
, (void *)task_name
);
433 /* set thread extra info
437 * calculate length as:
438 * state length + address length + errno length + formatter length
440 extra_info_length
+= strlen((void *)state_name
) + 8 + 8 + 8;
441 rtos
->thread_details
[i
].extra_info_str
= malloc(extra_info_length
+ 1);
442 if (NULL
== rtos
->thread_details
[i
].extra_info_str
)
445 rtos
->thread_details
[i
].extra_info_str
, extra_info_length
, "%s : 0x%"PRIx32
" : %" PRIu32
,
446 state_name
, task_addr
, task_errno
448 /* set active thread */
449 if (active_td_addr
== task_addr
)
450 rtos
->current_thread
= task_id
;
456 * API function, get info of selected thread
458 static int mqx_get_thread_reg_list(
464 int64_t stack_ptr
= 0;
465 uint32_t my_task_addr
= 0;
466 uint32_t task_queue_addr
= 0;
467 uint32_t task_queue_size
= 0;
468 uint32_t kernel_data_addr
= 0;
470 *hex_reg_list
= NULL
;
471 if (thread_id
== 0) {
472 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id
);
475 if (ERROR_OK
!= mqx_is_scheduler_running(rtos
))
477 /* get kernel_data symbol */
478 if (ERROR_OK
!= mqx_get_symbol(
479 rtos
, mqx_VAL_mqx_kernel_data
, &kernel_data_addr
483 /* read kernel_data */
484 if (ERROR_OK
!= mqx_get_member(
485 rtos
, kernel_data_addr
, 0, 4, "_mqx_kernel_data", &kernel_data_addr
489 /* get task queue address */
490 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
491 /* get task queue size */
492 if (ERROR_OK
!= mqx_get_member(
493 rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
494 "kernel_data->TD_LIST.SIZE", &task_queue_size
498 /* search for taskid */
500 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
501 i
< (uint32_t)rtos
->thread_count
;
504 uint32_t tmp_address
= 0, task_addr
= 0;
505 uint32_t task_id
= 0;
506 /* set current taskpool address */
507 tmp_address
= taskpool_addr
;
508 if (ERROR_OK
!= mqx_get_member(
509 rtos
, tmp_address
, MQX_TASK_OFFSET_NEXT
, 4,
510 "td_struct_ptr->NEXT", &taskpool_addr
514 /* get task address from taskpool */
515 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
516 /* get value of td_struct->TASK_ID */
517 if (ERROR_OK
!= mqx_get_member(
518 rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
519 "td_struct_ptr->TASK_ID", &task_id
523 /* found taskid, break */
524 if (task_id
== thread_id
) {
525 my_task_addr
= task_addr
;
530 LOG_ERROR("MQX_RTOS - threadid %" PRId64
" does not match any task", thread_id
);
533 /* get task stack head address */
534 if (ERROR_OK
!= mqx_get_member(
535 rtos
, my_task_addr
, MQX_TASK_OFFSET_STACK
, 4, "task->STACK_PTR", &stack_ptr
539 return rtos_generic_stack_read(
540 rtos
->target
, ((struct mqx_params
*)rtos
->rtos_specific_params
)->stacking_info
, stack_ptr
, hex_reg_list
544 /* API function, export list of required symbols */
545 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t
*symbol_list
[])
547 *symbol_list
= calloc(ARRAY_SIZE(mqx_symbol_list
), sizeof(symbol_table_elem_t
));
548 if (NULL
== *symbol_list
)
550 /* export required symbols */
551 for (int i
= 0; i
< (int)(ARRAY_SIZE(mqx_symbol_list
)); i
++)
552 (*symbol_list
)[i
].symbol_name
= mqx_symbol_list
[i
];
556 struct rtos_type mqx_rtos
= {
558 .detect_rtos
= mqx_detect_rtos
,
559 .create
= mqx_create
,
560 .update_threads
= mqx_update_threads
,
561 .get_thread_reg_list
= mqx_get_thread_reg_list
,
562 .get_symbol_list_to_lookup
= mqx_get_symbol_list_to_lookup
,