1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2014 by Marian Cingel *
5 * cingel.marian@gmail.com *
6 ***************************************************************************/
13 #include <helper/time_support.h>
14 #include <jtag/jtag.h>
15 #include "target/target.h"
16 #include "target/target_type.h"
18 #include "helper/log.h"
19 #include "helper/types.h"
20 #include "rtos_mqx_stackings.h"
23 #define MQX_THREAD_NAME_LENGTH (255)
24 #define MQX_KERNEL_OFFSET_TDLIST (0x0108)
25 #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050)
26 #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C)
27 #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000)
28 #define MQX_QUEUE_OFFSET_SIZE (0x0008)
29 #define MQX_TASK_OFFSET_STATE (0x0008)
30 #define MQX_TASK_OFFSET_ID (0x000c)
31 #define MQX_TASK_OFFSET_TEMPLATE (0x0068)
32 #define MQX_TASK_OFFSET_STACK (0x0014)
33 #define MQX_TASK_OFFSET_TDLIST (0x006C)
34 #define MQX_TASK_OFFSET_NEXT (0x0000)
35 #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010)
36 #define MQX_TASK_OFFSET_ERROR_CODE (0x005C)
37 #define MQX_TASK_STATE_MASK (0xFFF)
41 MQX_VAL_MQX_KERNEL_DATA
,
42 MQX_VAL_MQX_INIT_STRUCT
,
50 const char *target_name
;
51 const enum mqx_arch target_arch
;
52 const struct rtos_register_stacking
*stacking_info
;
61 static const struct mqx_state mqx_states
[] = {
63 { 0x0003, "BLOCKED" },
64 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
65 { 0x0007, "RCV_ANY_BLOCKED" },
67 { 0x000B, "UNHANDLED_INT_BLOCKED" },
68 { 0x000D, "SEND_BLOCKED" },
69 { 0x000F, "BREAKPOINT_BLOCKED" },
70 { 0x0211, "IO_BLOCKED" },
71 { 0x0021, "SEM_BLOCKED" },
72 { 0x0223, "MUTEX_BLOCKED" },
73 { 0x0025, "EVENT_BLOCKED" },
74 { 0x0229, "TASK_QUEUE_BLOCKED" },
75 { 0x042B, "LWSEM_BLOCKED" },
76 { 0x042D, "LWEVENT_BLOCKED" },
79 static const char * const mqx_symbol_list
[] = {
85 static const struct mqx_params mqx_params_list
[] = {
86 { "cortex_m", mqx_arch_cortexm
, &rtos_mqx_arm_v7m_stacking
},
90 * Perform simple address check to avoid bus fault.
92 static int mqx_valid_address_check(
97 enum mqx_arch arch_type
= ((struct mqx_params
*)rtos
->rtos_specific_params
)->target_arch
;
98 const char *targetname
= ((struct mqx_params
*)rtos
->rtos_specific_params
)->target_name
;
100 /* Cortex-M address range */
101 if (arch_type
== mqx_arch_cortexm
) {
103 /* code and sram area */
104 (address
&& address
<= 0x3FFFFFFFu
) ||
105 /* external ram area*/
106 (address
>= 0x6000000u
&& address
<= 0x9FFFFFFFu
)
112 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname
);
117 * Wrapper of 'target_read_buffer' fn.
118 * Include address check.
120 static int mqx_target_read_buffer(
121 struct target
*target
,
127 int status
= mqx_valid_address_check(target
->rtos
, address
);
128 if (status
!= ERROR_OK
) {
129 LOG_WARNING("MQX RTOS - target address 0x%" PRIx32
" is not allowed to read", address
);
132 status
= target_read_buffer(target
, address
, size
, buffer
);
133 if (status
!= ERROR_OK
) {
134 LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32
" failed", address
);
141 * Get symbol address if present
143 static int mqx_get_symbol(
145 enum mqx_symbols symbol
,
149 /* TODO: additional check ?? */
150 (*(int *)result
) = (uint32_t)rtos
->symbols
[symbol
].address
;
155 * Get value of struct member by passing
156 * member offset, width and name (debug purpose)
158 static int mqx_get_member(
160 const uint32_t base_address
,
161 int32_t member_offset
,
162 int32_t member_width
,
163 const char *member_name
,
167 int status
= ERROR_FAIL
;
168 status
= mqx_target_read_buffer(
169 rtos
->target
, base_address
+ member_offset
, member_width
, result
171 if (status
!= ERROR_OK
)
172 LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32
,
173 member_name
, (uint32_t)(base_address
+ member_offset
));
178 * Check whether scheduler started
180 static int mqx_is_scheduler_running(
184 uint32_t kernel_data_symbol
= 0;
185 uint32_t kernel_data_addr
= 0;
186 uint32_t system_td_addr
= 0;
187 uint32_t active_td_addr
= 0;
188 uint32_t capability_value
= 0;
190 /* get '_mqx_kernel_data' symbol */
191 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_symbol
) != ERROR_OK
)
194 /* get '_mqx_kernel_data' */
195 if (mqx_get_member(rtos
, kernel_data_symbol
, 0, 4,
196 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
199 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
200 if (kernel_data_addr
== 0 || kernel_data_addr
== (uint32_t)(-1))
202 /* get kernel_data->ADDRESSING_CAPABILITY */
203 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_CAPABILITY
, 4,
204 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value
) != ERROR_OK
)
207 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
208 it suppose to be set to value 8 */
209 if (capability_value
!= 8) {
210 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
214 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_ACTIVE_TASK
, 4,
215 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
) != ERROR_OK
)
218 /* active task is system task, scheduler has not not run yet */
219 system_td_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_SYSTEM_TASK
;
220 if (active_td_addr
== system_td_addr
) {
221 LOG_WARNING("MQX RTOS - scheduler does not run");
228 * API function, return true if MQX is present
230 static bool mqx_detect_rtos(
231 struct target
*target
235 (target
->rtos
->symbols
) &&
236 (target
->rtos
->symbols
[MQX_VAL_MQX_KERNEL_DATA
].address
!= 0)
244 * API function, pass MQX extra info to context data
246 static int mqx_create(
247 struct target
*target
250 /* check target name against supported architectures */
251 for (unsigned int i
= 0; i
< ARRAY_SIZE(mqx_params_list
); i
++) {
252 if (strcmp(mqx_params_list
[i
].target_name
, target
->type
->name
) == 0) {
253 target
->rtos
->rtos_specific_params
= (void *)&mqx_params_list
[i
];
254 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
258 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target
->type
->name
);
263 * API function, update list of threads
265 static int mqx_update_threads(
269 uint32_t task_queue_addr
= 0;
270 uint32_t kernel_data_addr
= 0;
271 uint16_t task_queue_size
= 0;
272 uint32_t active_td_addr
= 0;
274 if (!rtos
->rtos_specific_params
)
281 rtos_free_threadlist(rtos
);
282 /* check scheduler */
283 if (mqx_is_scheduler_running(rtos
) != ERROR_OK
)
285 /* get kernel_data symbol */
286 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_addr
) != ERROR_OK
)
289 /* read kernel_data */
290 if (mqx_get_member(rtos
, kernel_data_addr
, 0, 4,
291 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
294 /* get task queue address */
295 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
296 /* get task queue size */
297 if (mqx_get_member(rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
298 "kernel_data->TD_LIST.SIZE", &task_queue_size
) != ERROR_OK
)
302 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_ACTIVE_TASK
, 4,
303 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
) != ERROR_OK
)
306 /* setup threads info */
307 rtos
->thread_count
= task_queue_size
;
308 rtos
->current_thread
= 0;
309 rtos
->thread_details
= calloc(rtos
->thread_count
, sizeof(struct thread_detail
));
310 if (!rtos
->thread_details
)
313 /* loop over each task and setup thread details,
314 the current_taskpool_addr is set to queue head
315 NOTE: debugging functions task create/destroy
316 might cause to show invalid data.
319 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
320 i
< (uint32_t)rtos
->thread_count
;
323 uint8_t task_name
[MQX_THREAD_NAME_LENGTH
+ 1];
324 uint32_t task_addr
= 0, task_template
= 0, task_state
= 0;
325 uint32_t task_name_addr
= 0, task_id
= 0, task_errno
= 0;
326 uint32_t state_index
= 0;
327 uint32_t extra_info_length
= 0;
328 char *state_name
= "Unknown";
330 /* set current taskpool address */
331 if (mqx_get_member(rtos
, taskpool_addr
, MQX_TASK_OFFSET_NEXT
, 4,
332 "td_struct_ptr->NEXT", &taskpool_addr
) != ERROR_OK
)
335 /* get task address from taskpool */
336 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
337 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
338 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_TEMPLATE
, 4,
339 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
) != ERROR_OK
)
342 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
343 if (mqx_get_member(rtos
, task_template
, MQX_TASK_TEMPLATE_OFFSET_NAME
, 4,
344 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
) != ERROR_OK
)
347 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
348 if (mqx_get_member(rtos
, task_name_addr
, 0, MQX_THREAD_NAME_LENGTH
,
349 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
) != ERROR_OK
)
352 /* always terminate last character by force,
353 otherwise openocd might fail if task_name
354 has corrupted data */
355 task_name
[MQX_THREAD_NAME_LENGTH
] = '\0';
356 /* get value of 'td_struct_ptr->TASK_ID' */
357 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
358 "td_struct_ptr->TASK_ID", &task_id
) != ERROR_OK
)
362 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ERROR_CODE
, 4,
363 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
) != ERROR_OK
)
366 /* get value of 'td_struct_ptr->STATE' */
367 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_STATE
, 4,
368 "td_struct_ptr->STATE", &task_state
) != ERROR_OK
)
371 task_state
&= MQX_TASK_STATE_MASK
;
372 /* and search for defined state */
373 for (state_index
= 0; state_index
< ARRAY_SIZE(mqx_states
); state_index
++) {
374 if (mqx_states
[state_index
].state
== task_state
) {
375 state_name
= mqx_states
[state_index
].name
;
380 /* setup thread details struct */
381 rtos
->thread_details
[i
].threadid
= task_id
;
382 rtos
->thread_details
[i
].exists
= true;
383 /* set thread name */
384 rtos
->thread_details
[i
].thread_name_str
= malloc(strlen((void *)task_name
) + 1);
385 if (!rtos
->thread_details
[i
].thread_name_str
)
387 strcpy(rtos
->thread_details
[i
].thread_name_str
, (void *)task_name
);
388 /* set thread extra info
392 * calculate length as:
393 * state length + address length + errno length + formatter length
395 extra_info_length
+= strlen((void *)state_name
) + 7 + 13 + 8 + 15 + 8;
396 rtos
->thread_details
[i
].extra_info_str
= malloc(extra_info_length
+ 1);
397 if (!rtos
->thread_details
[i
].extra_info_str
)
399 snprintf(rtos
->thread_details
[i
].extra_info_str
, extra_info_length
,
400 "State: %s, Address: 0x%" PRIx32
", Error Code: %" PRIu32
,
401 state_name
, task_addr
, task_errno
403 /* set active thread */
404 if (active_td_addr
== task_addr
)
405 rtos
->current_thread
= task_id
;
411 * API function, get info of selected thread
413 static int mqx_get_thread_reg_list(
416 struct rtos_reg
**reg_list
,
420 int64_t stack_ptr
= 0;
421 uint32_t my_task_addr
= 0;
422 uint32_t task_queue_addr
= 0;
423 uint32_t task_queue_size
= 0;
424 uint32_t kernel_data_addr
= 0;
426 if (thread_id
== 0) {
427 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id
);
430 if (mqx_is_scheduler_running(rtos
) != ERROR_OK
)
432 /* get kernel_data symbol */
433 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_addr
) != ERROR_OK
)
436 /* read kernel_data */
437 if (mqx_get_member(rtos
, kernel_data_addr
, 0, 4,
438 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
441 /* get task queue address */
442 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
443 /* get task queue size */
444 if (mqx_get_member(rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
445 "kernel_data->TD_LIST.SIZE", &task_queue_size
) != ERROR_OK
)
448 /* search for taskid */
450 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
451 i
< (uint32_t)rtos
->thread_count
;
454 uint32_t tmp_address
= 0, task_addr
= 0;
455 uint32_t task_id
= 0;
456 /* set current taskpool address */
457 tmp_address
= taskpool_addr
;
458 if (mqx_get_member(rtos
, tmp_address
, MQX_TASK_OFFSET_NEXT
, 4,
459 "td_struct_ptr->NEXT", &taskpool_addr
) != ERROR_OK
)
462 /* get task address from taskpool */
463 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
464 /* get value of td_struct->TASK_ID */
465 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
466 "td_struct_ptr->TASK_ID", &task_id
) != ERROR_OK
)
469 /* found taskid, break */
470 if (task_id
== thread_id
) {
471 my_task_addr
= task_addr
;
476 LOG_ERROR("MQX_RTOS - threadid %" PRId64
" does not match any task", thread_id
);
479 /* get task stack head address */
480 if (mqx_get_member(rtos
, my_task_addr
, MQX_TASK_OFFSET_STACK
, 4,
481 "task->STACK_PTR", &stack_ptr
) != ERROR_OK
)
484 return rtos_generic_stack_read(
485 rtos
->target
, ((struct mqx_params
*)rtos
->rtos_specific_params
)->stacking_info
, stack_ptr
, reg_list
, num_regs
489 /* API function, export list of required symbols */
490 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
492 *symbol_list
= calloc(ARRAY_SIZE(mqx_symbol_list
), sizeof(struct symbol_table_elem
));
495 /* export required symbols */
496 for (int i
= 0; i
< (int)(ARRAY_SIZE(mqx_symbol_list
)); i
++)
497 (*symbol_list
)[i
].symbol_name
= mqx_symbol_list
[i
];
501 struct rtos_type mqx_rtos
= {
503 .detect_rtos
= mqx_detect_rtos
,
504 .create
= mqx_create
,
505 .update_threads
= mqx_update_threads
,
506 .get_thread_reg_list
= mqx_get_thread_reg_list
,
507 .get_symbol_list_to_lookup
= mqx_get_symbol_list_to_lookup
,