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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
24 #include <helper/time_support.h>
25 #include <jtag/jtag.h>
26 #include "target/target.h"
27 #include "target/target_type.h"
29 #include "helper/log.h"
30 #include "helper/types.h"
31 #include "rtos_mqx_stackings.h"
34 #define MQX_THREAD_NAME_LENGTH (255)
35 #define MQX_KERNEL_OFFSET_TDLIST (0x0108)
36 #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050)
37 #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C)
38 #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000)
39 #define MQX_QUEUE_OFFSET_SIZE (0x0008)
40 #define MQX_TASK_OFFSET_STATE (0x0008)
41 #define MQX_TASK_OFFSET_ID (0x000c)
42 #define MQX_TASK_OFFSET_TEMPLATE (0x0068)
43 #define MQX_TASK_OFFSET_STACK (0x0014)
44 #define MQX_TASK_OFFSET_TDLIST (0x006C)
45 #define MQX_TASK_OFFSET_NEXT (0x0000)
46 #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010)
47 #define MQX_TASK_OFFSET_ERROR_CODE (0x005C)
48 #define MQX_TASK_STATE_MASK (0xFFF)
52 MQX_VAL_MQX_KERNEL_DATA
,
53 MQX_VAL_MQX_INIT_STRUCT
,
61 const char *target_name
;
62 const enum mqx_arch target_arch
;
63 const struct rtos_register_stacking
*stacking_info
;
72 static const struct mqx_state mqx_states
[] = {
74 { 0x0003, "BLOCKED" },
75 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
76 { 0x0007, "RCV_ANY_BLOCKED" },
78 { 0x000B, "UNHANDLED_INT_BLOCKED" },
79 { 0x000D, "SEND_BLOCKED" },
80 { 0x000F, "BREAKPOINT_BLOCKED" },
81 { 0x0211, "IO_BLOCKED" },
82 { 0x0021, "SEM_BLOCKED" },
83 { 0x0223, "MUTEX_BLOCKED" },
84 { 0x0025, "EVENT_BLOCKED" },
85 { 0x0229, "TASK_QUEUE_BLOCKED" },
86 { 0x042B, "LWSEM_BLOCKED" },
87 { 0x042D, "LWEVENT_BLOCKED" },
90 static const char * const mqx_symbol_list
[] = {
96 static const struct mqx_params mqx_params_list
[] = {
97 { "cortex_m", mqx_arch_cortexm
, &rtos_mqx_arm_v7m_stacking
},
101 * Perform simple address check to avoid bus fault.
103 static int mqx_valid_address_check(
108 enum mqx_arch arch_type
= ((struct mqx_params
*)rtos
->rtos_specific_params
)->target_arch
;
109 const char *targetname
= ((struct mqx_params
*)rtos
->rtos_specific_params
)->target_name
;
111 /* Cortex-M address range */
112 if (arch_type
== mqx_arch_cortexm
) {
114 /* code and sram area */
115 (address
&& address
<= 0x3FFFFFFFu
) ||
116 /* external ram area*/
117 (address
>= 0x6000000u
&& address
<= 0x9FFFFFFFu
)
123 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname
);
128 * Wrapper of 'target_read_buffer' fn.
129 * Include address check.
131 static int mqx_target_read_buffer(
132 struct target
*target
,
138 int status
= mqx_valid_address_check(target
->rtos
, address
);
139 if (status
!= ERROR_OK
) {
140 LOG_WARNING("MQX RTOS - target address 0x%" PRIx32
" is not allowed to read", address
);
143 status
= target_read_buffer(target
, address
, size
, buffer
);
144 if (status
!= ERROR_OK
) {
145 LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32
" failed", address
);
152 * Get symbol address if present
154 static int mqx_get_symbol(
156 enum mqx_symbols symbol
,
160 /* TODO: additional check ?? */
161 (*(int *)result
) = (uint32_t)rtos
->symbols
[symbol
].address
;
166 * Get value of struct member by passing
167 * member offset, width and name (debug purpose)
169 static int mqx_get_member(
171 const uint32_t base_address
,
172 int32_t member_offset
,
173 int32_t member_width
,
174 const char *member_name
,
178 int status
= ERROR_FAIL
;
179 status
= mqx_target_read_buffer(
180 rtos
->target
, base_address
+ member_offset
, member_width
, result
182 if (status
!= ERROR_OK
)
183 LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32
,
184 member_name
, (uint32_t)(base_address
+ member_offset
));
189 * Check whether scheduler started
191 static int mqx_is_scheduler_running(
195 uint32_t kernel_data_symbol
= 0;
196 uint32_t kernel_data_addr
= 0;
197 uint32_t system_td_addr
= 0;
198 uint32_t active_td_addr
= 0;
199 uint32_t capability_value
= 0;
201 /* get '_mqx_kernel_data' symbol */
202 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_symbol
) != ERROR_OK
)
205 /* get '_mqx_kernel_data' */
206 if (mqx_get_member(rtos
, kernel_data_symbol
, 0, 4,
207 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
210 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
211 if (kernel_data_addr
== 0 || kernel_data_addr
== (uint32_t)(-1))
213 /* get kernel_data->ADDRESSING_CAPABILITY */
214 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_CAPABILITY
, 4,
215 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value
) != ERROR_OK
)
218 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
219 it suppose to be set to value 8 */
220 if (capability_value
!= 8) {
221 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
225 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_ACTIVE_TASK
, 4,
226 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
) != ERROR_OK
)
229 /* active task is system task, scheduler has not not run yet */
230 system_td_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_SYSTEM_TASK
;
231 if (active_td_addr
== system_td_addr
) {
232 LOG_WARNING("MQX RTOS - scheduler does not run");
239 * API function, return true if MQX is present
241 static bool mqx_detect_rtos(
242 struct target
*target
246 (target
->rtos
->symbols
!= NULL
) &&
247 (target
->rtos
->symbols
[MQX_VAL_MQX_KERNEL_DATA
].address
!= 0)
255 * API function, pass MQX extra info to context data
257 static int mqx_create(
258 struct target
*target
261 /* check target name against supported architectures */
262 for (unsigned int i
= 0; i
< ARRAY_SIZE(mqx_params_list
); i
++) {
263 if (0 == strcmp(mqx_params_list
[i
].target_name
, target
->type
->name
)) {
264 target
->rtos
->rtos_specific_params
= (void *)&mqx_params_list
[i
];
265 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
269 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target
->type
->name
);
274 * API function, update list of threads
276 static int mqx_update_threads(
280 uint32_t task_queue_addr
= 0;
281 uint32_t kernel_data_addr
= 0;
282 uint16_t task_queue_size
= 0;
283 uint32_t active_td_addr
= 0;
285 if (!rtos
->rtos_specific_params
)
292 rtos_free_threadlist(rtos
);
293 /* check scheduler */
294 if (ERROR_OK
!= mqx_is_scheduler_running(rtos
))
296 /* get kernel_data symbol */
297 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_addr
) != ERROR_OK
)
300 /* read kernel_data */
301 if (mqx_get_member(rtos
, kernel_data_addr
, 0, 4,
302 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
305 /* get task queue address */
306 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
307 /* get task queue size */
308 if (mqx_get_member(rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
309 "kernel_data->TD_LIST.SIZE", &task_queue_size
) != ERROR_OK
)
313 if (mqx_get_member(rtos
, kernel_data_addr
, MQX_KERNEL_OFFSET_ACTIVE_TASK
, 4,
314 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
) != ERROR_OK
)
317 /* setup threads info */
318 rtos
->thread_count
= task_queue_size
;
319 rtos
->current_thread
= 0;
320 rtos
->thread_details
= calloc(rtos
->thread_count
, sizeof(struct thread_detail
));
321 if (!rtos
->thread_details
)
324 /* loop over each task and setup thread details,
325 the current_taskpool_addr is set to queue head
326 NOTE: debugging functions task create/destroy
327 might cause to show invalid data.
330 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
331 i
< (uint32_t)rtos
->thread_count
;
334 uint8_t task_name
[MQX_THREAD_NAME_LENGTH
+ 1];
335 uint32_t task_addr
= 0, task_template
= 0, task_state
= 0;
336 uint32_t task_name_addr
= 0, task_id
= 0, task_errno
= 0;
337 uint32_t state_index
= 0;
338 uint32_t extra_info_length
= 0;
339 char *state_name
= "Unknown";
341 /* set current taskpool address */
342 if (mqx_get_member(rtos
, taskpool_addr
, MQX_TASK_OFFSET_NEXT
, 4,
343 "td_struct_ptr->NEXT", &taskpool_addr
) != ERROR_OK
)
346 /* get task address from taskpool */
347 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
348 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
349 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_TEMPLATE
, 4,
350 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
) != ERROR_OK
)
353 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
354 if (mqx_get_member(rtos
, task_template
, MQX_TASK_TEMPLATE_OFFSET_NAME
, 4,
355 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
) != ERROR_OK
)
358 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
359 if (mqx_get_member(rtos
, task_name_addr
, 0, MQX_THREAD_NAME_LENGTH
,
360 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
) != ERROR_OK
)
363 /* always terminate last character by force,
364 otherwise openocd might fail if task_name
365 has corrupted data */
366 task_name
[MQX_THREAD_NAME_LENGTH
] = '\0';
367 /* get value of 'td_struct_ptr->TASK_ID' */
368 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
369 "td_struct_ptr->TASK_ID", &task_id
) != ERROR_OK
)
373 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ERROR_CODE
, 4,
374 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
) != ERROR_OK
)
377 /* get value of 'td_struct_ptr->STATE' */
378 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_STATE
, 4,
379 "td_struct_ptr->STATE", &task_state
) != ERROR_OK
)
382 task_state
&= MQX_TASK_STATE_MASK
;
383 /* and search for defined state */
384 for (state_index
= 0; state_index
< ARRAY_SIZE(mqx_states
); state_index
++) {
385 if (mqx_states
[state_index
].state
== task_state
) {
386 state_name
= mqx_states
[state_index
].name
;
391 /* setup thread details struct */
392 rtos
->thread_details
[i
].threadid
= task_id
;
393 rtos
->thread_details
[i
].exists
= true;
394 /* set thread name */
395 rtos
->thread_details
[i
].thread_name_str
= malloc(strlen((void *)task_name
) + 1);
396 if (NULL
== rtos
->thread_details
[i
].thread_name_str
)
398 strcpy(rtos
->thread_details
[i
].thread_name_str
, (void *)task_name
);
399 /* set thread extra info
403 * calculate length as:
404 * state length + address length + errno length + formatter length
406 extra_info_length
+= strlen((void *)state_name
) + 7 + 13 + 8 + 15 + 8;
407 rtos
->thread_details
[i
].extra_info_str
= malloc(extra_info_length
+ 1);
408 if (NULL
== rtos
->thread_details
[i
].extra_info_str
)
410 snprintf(rtos
->thread_details
[i
].extra_info_str
, extra_info_length
,
411 "State: %s, Address: 0x%" PRIx32
", Error Code: %" PRIu32
,
412 state_name
, task_addr
, task_errno
414 /* set active thread */
415 if (active_td_addr
== task_addr
)
416 rtos
->current_thread
= task_id
;
422 * API function, get info of selected thread
424 static int mqx_get_thread_reg_list(
427 struct rtos_reg
**reg_list
,
431 int64_t stack_ptr
= 0;
432 uint32_t my_task_addr
= 0;
433 uint32_t task_queue_addr
= 0;
434 uint32_t task_queue_size
= 0;
435 uint32_t kernel_data_addr
= 0;
437 if (thread_id
== 0) {
438 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id
);
441 if (ERROR_OK
!= mqx_is_scheduler_running(rtos
))
443 /* get kernel_data symbol */
444 if (mqx_get_symbol(rtos
, MQX_VAL_MQX_KERNEL_DATA
, &kernel_data_addr
) != ERROR_OK
)
447 /* read kernel_data */
448 if (mqx_get_member(rtos
, kernel_data_addr
, 0, 4,
449 "_mqx_kernel_data", &kernel_data_addr
) != ERROR_OK
)
452 /* get task queue address */
453 task_queue_addr
= kernel_data_addr
+ MQX_KERNEL_OFFSET_TDLIST
;
454 /* get task queue size */
455 if (mqx_get_member(rtos
, task_queue_addr
, MQX_QUEUE_OFFSET_SIZE
, 2,
456 "kernel_data->TD_LIST.SIZE", &task_queue_size
) != ERROR_OK
)
459 /* search for taskid */
461 uint32_t i
= 0, taskpool_addr
= task_queue_addr
;
462 i
< (uint32_t)rtos
->thread_count
;
465 uint32_t tmp_address
= 0, task_addr
= 0;
466 uint32_t task_id
= 0;
467 /* set current taskpool address */
468 tmp_address
= taskpool_addr
;
469 if (mqx_get_member(rtos
, tmp_address
, MQX_TASK_OFFSET_NEXT
, 4,
470 "td_struct_ptr->NEXT", &taskpool_addr
) != ERROR_OK
)
473 /* get task address from taskpool */
474 task_addr
= taskpool_addr
- MQX_TASK_OFFSET_TDLIST
;
475 /* get value of td_struct->TASK_ID */
476 if (mqx_get_member(rtos
, task_addr
, MQX_TASK_OFFSET_ID
, 4,
477 "td_struct_ptr->TASK_ID", &task_id
) != ERROR_OK
)
480 /* found taskid, break */
481 if (task_id
== thread_id
) {
482 my_task_addr
= task_addr
;
487 LOG_ERROR("MQX_RTOS - threadid %" PRId64
" does not match any task", thread_id
);
490 /* get task stack head address */
491 if (mqx_get_member(rtos
, my_task_addr
, MQX_TASK_OFFSET_STACK
, 4,
492 "task->STACK_PTR", &stack_ptr
) != ERROR_OK
)
495 return rtos_generic_stack_read(
496 rtos
->target
, ((struct mqx_params
*)rtos
->rtos_specific_params
)->stacking_info
, stack_ptr
, reg_list
, num_regs
500 /* API function, export list of required symbols */
501 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
503 *symbol_list
= calloc(ARRAY_SIZE(mqx_symbol_list
), sizeof(struct symbol_table_elem
));
504 if (NULL
== *symbol_list
)
506 /* export required symbols */
507 for (int i
= 0; i
< (int)(ARRAY_SIZE(mqx_symbol_list
)); i
++)
508 (*symbol_list
)[i
].symbol_name
= mqx_symbol_list
[i
];
512 struct rtos_type mqx_rtos
= {
514 .detect_rtos
= mqx_detect_rtos
,
515 .create
= mqx_create
,
516 .update_threads
= mqx_update_threads
,
517 .get_thread_reg_list
= mqx_get_thread_reg_list
,
518 .get_symbol_list_to_lookup
= mqx_get_symbol_list_to_lookup
,
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)