Fix spelling of ARM Cortex
[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 if (!rtos->rtos_specific_params)
296 return -3;
297
298 if (!rtos->symbols)
299 return -4;
300
301 /* clear old data */
302 rtos_free_threadlist(rtos);
303 /* check scheduler */
304 if (ERROR_OK != mqx_is_scheduler_running(rtos))
305 return ERROR_FAIL;
306 /* get kernel_data symbol */
307 if (ERROR_OK != mqx_get_symbol(
308 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
309 )) {
310 return ERROR_FAIL;
311 }
312 /* read kernel_data */
313 if (ERROR_OK != mqx_get_member(
314 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
315 )) {
316 return ERROR_FAIL;
317 }
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
324 )) {
325 return ERROR_FAIL;
326 }
327 /* get active ptr */
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
331 )) {
332 return ERROR_FAIL;
333 }
334
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)
340 return ERROR_FAIL;
341
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.
346 */
347 for (
348 uint32_t i = 0, taskpool_addr = task_queue_addr;
349 i < (uint32_t)rtos->thread_count;
350 i++
351 ) {
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";
358
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
363 )) {
364 return ERROR_FAIL;
365 }
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
372 )) {
373 return ERROR_FAIL;
374 }
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
379 )) {
380 return ERROR_FAIL;
381 }
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
386 )) {
387 return ERROR_FAIL;
388 }
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
397 )) {
398 return ERROR_FAIL;
399 }
400 /* get task errno */
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
404 )) {
405 return ERROR_FAIL;
406 }
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
411 )) {
412 return ERROR_FAIL;
413 }
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;
420 break;
421 }
422 }
423
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)
431 return ERROR_FAIL;
432 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
433 /* set thread extra info
434 * - task state
435 * - task address
436 * - task errno
437 * calculate length as:
438 * state length + address length + errno length + formatter length
439 */
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)
443 return ERROR_FAIL;
444 snprintf(
445 rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32,
446 state_name, task_addr, task_errno
447 );
448 /* set active thread */
449 if (active_td_addr == task_addr)
450 rtos->current_thread = task_id;
451 }
452 return ERROR_OK;
453 }
454
455 /*
456 * API function, get info of selected thread
457 */
458 static int mqx_get_thread_reg_list(
459 struct rtos *rtos,
460 int64_t thread_id,
461 char **hex_reg_list
462 )
463 {
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;
469
470 *hex_reg_list = NULL;
471 if (thread_id == 0) {
472 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
473 return ERROR_FAIL;
474 }
475 if (ERROR_OK != mqx_is_scheduler_running(rtos))
476 return ERROR_FAIL;
477 /* get kernel_data symbol */
478 if (ERROR_OK != mqx_get_symbol(
479 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
480 )) {
481 return ERROR_FAIL;
482 }
483 /* read kernel_data */
484 if (ERROR_OK != mqx_get_member(
485 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
486 )) {
487 return ERROR_FAIL;
488 }
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
495 )) {
496 return ERROR_FAIL;
497 }
498 /* search for taskid */
499 for (
500 uint32_t i = 0, taskpool_addr = task_queue_addr;
501 i < (uint32_t)rtos->thread_count;
502 i++
503 ) {
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
511 )) {
512 return ERROR_FAIL;
513 }
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
520 )) {
521 return ERROR_FAIL;
522 }
523 /* found taskid, break */
524 if (task_id == thread_id) {
525 my_task_addr = task_addr;
526 break;
527 }
528 }
529 if (!my_task_addr) {
530 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
531 return ERROR_FAIL;
532 }
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
536 )) {
537 return ERROR_FAIL;
538 }
539 return rtos_generic_stack_read(
540 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
541 );
542 }
543
544 /* API function, export list of required symbols */
545 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
546 {
547 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t));
548 if (NULL == *symbol_list)
549 return ERROR_FAIL;
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];
553 return ERROR_OK;
554 }
555
556 struct rtos_type mqx_rtos = {
557 .name = "mqx",
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,
563 };

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)