bbb96b2f9ad1ec05200a5ad1acda7ce8c20b0e84
[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%X 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%X 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%X", member_name, base_address + member_offset);
185 return status;
186 }
187
188 /*
189 * Check whether scheduler started
190 */
191 static int mqx_is_scheduler_running(
192 struct rtos *rtos
193 )
194 {
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;
200
201 /* get '_mqx_kernel_data' symbol */
202 if (ERROR_OK != mqx_get_symbol(
203 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_symbol
204 )) {
205 return ERROR_FAIL;
206 }
207 /* get '_mqx_kernel_data' */
208 if (ERROR_OK != mqx_get_member(
209 rtos, kernel_data_symbol, 0, 4,
210 "_mqx_kernel_data", &kernel_data_addr
211 )) {
212 return ERROR_FAIL;
213 }
214 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
215 if (0 == kernel_data_addr || (uint32_t)(-1) == kernel_data_addr)
216 return ERROR_FAIL;
217 /* get kernel_data->ADDRESSING_CAPABILITY */
218 if (ERROR_OK != mqx_get_member(
219 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4,
220 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value
221 )) {
222 return ERROR_FAIL;
223 }
224 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
225 it supose to be set to value 8 */
226 if (capability_value != 8) {
227 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
228 return ERROR_FAIL;
229 }
230 /* get active ptr */
231 if (ERROR_OK != mqx_get_member(
232 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
233 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
234 )) {
235 return ERROR_FAIL;
236 }
237 /* active task is system task, scheduler has not not run yet */
238 system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK;
239 if (active_td_addr == system_td_addr) {
240 LOG_WARNING("MQX RTOS - scheduler does not run");
241 return ERROR_FAIL;
242 }
243 return ERROR_OK;
244 }
245
246 /*
247 * API function, return 1 if MQX is present
248 */
249 static int mqx_detect_rtos(
250 struct target *target
251 )
252 {
253 if (
254 (target->rtos->symbols != NULL) &&
255 (target->rtos->symbols[mqx_VAL_mqx_kernel_data].address != 0)
256 ) {
257 return 1;
258 }
259 return 0;
260 }
261
262 /*
263 * API function, pass MQX extra info to context data
264 */
265 static int mqx_create(
266 struct target *target
267 )
268 {
269 /* check target name against supported architectures */
270 int mqx_params_list_num = (sizeof(mqx_params_list)/sizeof(struct mqx_params));
271 for (int i = 0; i < mqx_params_list_num; i++) {
272 if (0 == strcmp(mqx_params_list[i].target_name, target->type->name)) {
273 target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
274 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
275 return 0;
276 }
277 }
278 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
279 return -1;
280 }
281
282 /*
283 * API function, update list of threads
284 */
285 static int mqx_update_threads(
286 struct rtos *rtos
287 )
288 {
289 uint32_t task_queue_addr = 0;
290 uint32_t kernel_data_addr = 0;
291 uint16_t task_queue_size = 0;
292 uint32_t active_td_addr = 0;
293
294 /* clear old data */
295 rtos_free_threadlist(rtos);
296 /* check scheduler */
297 if (ERROR_OK != mqx_is_scheduler_running(rtos))
298 return ERROR_FAIL;
299 /* get kernel_data symbol */
300 if (ERROR_OK != mqx_get_symbol(
301 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
302 )) {
303 return ERROR_FAIL;
304 }
305 /* read kernel_data */
306 if (ERROR_OK != mqx_get_member(
307 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
308 )) {
309 return ERROR_FAIL;
310 }
311 /* get task queue address */
312 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
313 /* get task queue size */
314 if (ERROR_OK != mqx_get_member(
315 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
316 "kernel_data->TD_LIST.SIZE", &task_queue_size
317 )) {
318 return ERROR_FAIL;
319 }
320 /* get active ptr */
321 if (ERROR_OK != mqx_get_member(
322 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
323 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
324 )) {
325 return ERROR_FAIL;
326 }
327
328 /* setup threads info */
329 rtos->thread_count = task_queue_size;
330 rtos->current_thread = 0;
331 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
332 if (NULL == rtos->thread_details)
333 return ERROR_FAIL;
334
335 /* loop over each task and setup thread details,
336 the current_taskpool_addr is set to queue head
337 NOTE: debugging functions task create/destroy
338 might cause to show invalid data.
339 */
340 for (
341 uint32_t i = 0, taskpool_addr = task_queue_addr;
342 i < (uint32_t)rtos->thread_count;
343 i++
344 ) {
345 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
346 uint32_t task_addr = 0, task_template = 0, task_state = 0;
347 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
348 uint32_t state_index = 0, state_max = 0;
349 uint32_t extra_info_length = 0;
350 char *state_name = "unknown state";
351
352 /* set current taskpool address */
353 if (ERROR_OK != mqx_get_member(
354 rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
355 "td_struct_ptr->NEXT", &taskpool_addr
356 )) {
357 return ERROR_FAIL;
358 }
359 /* get task address from taskpool */
360 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
361 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
362 if (ERROR_OK != mqx_get_member(
363 rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
364 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
365 )) {
366 return ERROR_FAIL;
367 }
368 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
369 if (ERROR_OK != mqx_get_member(
370 rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
371 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
372 )) {
373 return ERROR_FAIL;
374 }
375 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
376 if (ERROR_OK != mqx_get_member(
377 rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
378 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
379 )) {
380 return ERROR_FAIL;
381 }
382 /* always terminate last character by force,
383 otherwise openocd might fail if task_name
384 has corrupted data */
385 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
386 /* get value of 'td_struct_ptr->TASK_ID' */
387 if (ERROR_OK != mqx_get_member(
388 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
389 "td_struct_ptr->TASK_ID", &task_id
390 )) {
391 return ERROR_FAIL;
392 }
393 /* get task errno */
394 if (ERROR_OK != mqx_get_member(
395 rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
396 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
397 )) {
398 return ERROR_FAIL;
399 }
400 /* get value of 'td_struct_ptr->STATE' */
401 if (ERROR_OK != mqx_get_member(
402 rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
403 "td_struct_ptr->STATE", &task_state
404 )) {
405 return ERROR_FAIL;
406 }
407 task_state &= MQX_TASK_STATE_MASK;
408 /* and search for defined state */
409 state_max = (sizeof(mqx_states)/sizeof(struct mqx_state));
410 for (state_index = 0; (state_index < state_max); state_index++) {
411 if (mqx_states[state_index].state == task_state) {
412 state_name = mqx_states[state_index].name;
413 break;
414 }
415 }
416
417 /* setup thread details struct */
418 rtos->thread_details[i].threadid = task_id;
419 rtos->thread_details[i].exists = true;
420 rtos->thread_details[i].display_str = NULL;
421 /* set thread name */
422 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
423 if (NULL == rtos->thread_details[i].thread_name_str)
424 return ERROR_FAIL;
425 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
426 /* set thread extra info
427 * - task state
428 * - task address
429 * - task errno
430 * calculate length as:
431 * state length + address length + errno length + formatter length
432 */
433 extra_info_length += strlen((void *)state_name) + 8 + 8 + 8;
434 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
435 if (NULL == rtos->thread_details[i].extra_info_str)
436 return ERROR_FAIL;
437 snprintf(
438 rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%x : %u",
439 state_name, task_addr, task_errno
440 );
441 /* set active thread */
442 if (active_td_addr == task_addr)
443 rtos->current_thread = task_id;
444 }
445 return ERROR_OK;
446 }
447
448 /*
449 * API function, get info of selected thread
450 */
451 static int mqx_get_thread_reg_list(
452 struct rtos *rtos,
453 int64_t thread_id,
454 char **hex_reg_list
455 )
456 {
457 int64_t stack_ptr = 0;
458 uint32_t my_task_addr = 0;
459 uint32_t task_queue_addr = 0;
460 uint32_t task_queue_size = 0;
461 uint32_t kernel_data_addr = 0;
462
463 *hex_reg_list = NULL;
464 if (thread_id == 0) {
465 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
466 return ERROR_FAIL;
467 }
468 if (ERROR_OK != mqx_is_scheduler_running(rtos))
469 return ERROR_FAIL;
470 /* get kernel_data symbol */
471 if (ERROR_OK != mqx_get_symbol(
472 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
473 )) {
474 return ERROR_FAIL;
475 }
476 /* read kernel_data */
477 if (ERROR_OK != mqx_get_member(
478 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
479 )) {
480 return ERROR_FAIL;
481 }
482 /* get task queue address */
483 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
484 /* get task queue size */
485 if (ERROR_OK != mqx_get_member(
486 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
487 "kernel_data->TD_LIST.SIZE", &task_queue_size
488 )) {
489 return ERROR_FAIL;
490 }
491 /* search for taskid */
492 for (
493 uint32_t i = 0, taskpool_addr = task_queue_addr;
494 i < (uint32_t)rtos->thread_count;
495 i++
496 ) {
497 uint32_t tmp_address = 0, task_addr = 0;
498 uint32_t task_id = 0;
499 /* set current taskpool address */
500 tmp_address = taskpool_addr;
501 if (ERROR_OK != mqx_get_member(
502 rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
503 "td_struct_ptr->NEXT", &taskpool_addr
504 )) {
505 return ERROR_FAIL;
506 }
507 /* get task address from taskpool */
508 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
509 /* get value of td_struct->TASK_ID */
510 if (ERROR_OK != mqx_get_member(
511 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
512 "td_struct_ptr->TASK_ID", &task_id
513 )) {
514 return ERROR_FAIL;
515 }
516 /* found taskid, break */
517 if (task_id == thread_id) {
518 my_task_addr = task_addr;
519 break;
520 }
521 }
522 if (!my_task_addr) {
523 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
524 return ERROR_FAIL;
525 }
526 /* get task stack head address */
527 if (ERROR_OK != mqx_get_member(
528 rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr
529 )) {
530 return ERROR_FAIL;
531 }
532 return rtos_generic_stack_read(
533 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
534 );
535 }
536
537 /* API function, export list of required symbols */
538 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
539 {
540 *symbol_list = malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(mqx_symbol_list));
541 if (NULL == *symbol_list)
542 return ERROR_FAIL;
543 /* export required symbols */
544 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
545 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
546 return ERROR_OK;
547 }
548
549 struct rtos_type mqx_rtos = {
550 .name = "mqx",
551 .detect_rtos = mqx_detect_rtos,
552 .create = mqx_create,
553 .update_threads = mqx_update_threads,
554 .get_thread_reg_list = mqx_get_thread_reg_list,
555 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
556 };

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)