Remove FSF address from GPL notices
[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, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <stdint.h>
24 #include <helper/time_support.h>
25 #include <jtag/jtag.h>
26 #include "target/target.h"
27 #include "target/target_type.h"
28 #include "rtos.h"
29 #include "helper/log.h"
30 #include "helper/types.h"
31 #include "rtos_mqx_stackings.h"
32
33 /* constants */
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)
49
50 /* types */
51 enum mqx_symbols {
52 mqx_VAL_mqx_kernel_data,
53 mqx_VAL_MQX_init_struct,
54 };
55
56 enum mqx_arch {
57 mqx_arch_cortexm,
58 };
59
60 struct mqx_params {
61 const char *target_name;
62 const enum mqx_arch target_arch;
63 const struct rtos_register_stacking *stacking_info;
64 };
65
66 struct mqx_state {
67 uint32_t state;
68 char *name;
69 };
70
71 /* local data */
72 static const struct mqx_state mqx_states[] = {
73 { 0x0002, "READY" },
74 { 0x0003, "BLOCKED" },
75 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
76 { 0x0007, "RCV_ANY_BLOCKED" },
77 { 0x0009, "DYING" },
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" },
88 };
89
90 static const char * const mqx_symbol_list[] = {
91 "_mqx_kernel_data",
92 "MQX_init_struct",
93 NULL
94 };
95
96 static const struct mqx_params mqx_params_list[] = {
97 { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking },
98 };
99
100 /*
101 * Perform simple address check to avoid bus fault.
102 */
103 static int mqx_valid_address_check(
104 struct rtos *rtos,
105 uint32_t address
106 )
107 {
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;
110
111 /* Cortex-M address range */
112 if (arch_type == mqx_arch_cortexm) {
113 if (
114 /* code and sram area */
115 (address && address <= 0x3FFFFFFFu) ||
116 /* external ram area*/
117 (address >= 0x6000000u && address <= 0x9FFFFFFFu)
118 ) {
119 return ERROR_OK;
120 }
121 return ERROR_FAIL;
122 }
123 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname);
124 return ERROR_FAIL;
125 }
126
127 /*
128 * Wrapper of 'target_read_buffer' fn.
129 * Include address check.
130 */
131 static int mqx_target_read_buffer(
132 struct target *target,
133 uint32_t address,
134 uint32_t size,
135 uint8_t *buffer
136 )
137 {
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);
141 return status;
142 }
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);
146 return status;
147 }
148 return ERROR_OK;
149 }
150
151 /*
152 * Get symbol address if present
153 */
154 static int mqx_get_symbol(
155 struct rtos *rtos,
156 enum mqx_symbols symbol,
157 void *result
158 )
159 {
160 /* TODO: additional check ?? */
161 (*(int *)result) = (uint32_t)rtos->symbols[symbol].address;
162 return ERROR_OK;
163 }
164
165 /*
166 * Get value of struct member by passing
167 * member offset, width and name (debug purpose)
168 */
169 static int mqx_get_member(
170 struct rtos *rtos,
171 const uint32_t base_address,
172 int32_t member_offset,
173 int32_t member_width,
174 const char *member_name,
175 void *result
176 )
177 {
178 int status = ERROR_FAIL;
179 status = mqx_target_read_buffer(
180 rtos->target, base_address + member_offset, member_width, result
181 );
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));
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 if (!rtos->rtos_specific_params)
295 return -3;
296
297 if (!rtos->symbols)
298 return -4;
299
300 /* clear old data */
301 rtos_free_threadlist(rtos);
302 /* check scheduler */
303 if (ERROR_OK != mqx_is_scheduler_running(rtos))
304 return ERROR_FAIL;
305 /* get kernel_data symbol */
306 if (ERROR_OK != mqx_get_symbol(
307 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
308 )) {
309 return ERROR_FAIL;
310 }
311 /* read kernel_data */
312 if (ERROR_OK != mqx_get_member(
313 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
314 )) {
315 return ERROR_FAIL;
316 }
317 /* get task queue address */
318 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
319 /* get task queue size */
320 if (ERROR_OK != mqx_get_member(
321 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
322 "kernel_data->TD_LIST.SIZE", &task_queue_size
323 )) {
324 return ERROR_FAIL;
325 }
326 /* get active ptr */
327 if (ERROR_OK != mqx_get_member(
328 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
329 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
330 )) {
331 return ERROR_FAIL;
332 }
333
334 /* setup threads info */
335 rtos->thread_count = task_queue_size;
336 rtos->current_thread = 0;
337 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
338 if (NULL == rtos->thread_details)
339 return ERROR_FAIL;
340
341 /* loop over each task and setup thread details,
342 the current_taskpool_addr is set to queue head
343 NOTE: debugging functions task create/destroy
344 might cause to show invalid data.
345 */
346 for (
347 uint32_t i = 0, taskpool_addr = task_queue_addr;
348 i < (uint32_t)rtos->thread_count;
349 i++
350 ) {
351 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
352 uint32_t task_addr = 0, task_template = 0, task_state = 0;
353 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
354 uint32_t state_index = 0, state_max = 0;
355 uint32_t extra_info_length = 0;
356 char *state_name = "unknown state";
357
358 /* set current taskpool address */
359 if (ERROR_OK != mqx_get_member(
360 rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
361 "td_struct_ptr->NEXT", &taskpool_addr
362 )) {
363 return ERROR_FAIL;
364 }
365 /* get task address from taskpool */
366 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
367 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
368 if (ERROR_OK != mqx_get_member(
369 rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
370 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
371 )) {
372 return ERROR_FAIL;
373 }
374 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
375 if (ERROR_OK != mqx_get_member(
376 rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
377 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
378 )) {
379 return ERROR_FAIL;
380 }
381 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
382 if (ERROR_OK != mqx_get_member(
383 rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
384 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
385 )) {
386 return ERROR_FAIL;
387 }
388 /* always terminate last character by force,
389 otherwise openocd might fail if task_name
390 has corrupted data */
391 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
392 /* get value of 'td_struct_ptr->TASK_ID' */
393 if (ERROR_OK != mqx_get_member(
394 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
395 "td_struct_ptr->TASK_ID", &task_id
396 )) {
397 return ERROR_FAIL;
398 }
399 /* get task errno */
400 if (ERROR_OK != mqx_get_member(
401 rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
402 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
403 )) {
404 return ERROR_FAIL;
405 }
406 /* get value of 'td_struct_ptr->STATE' */
407 if (ERROR_OK != mqx_get_member(
408 rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
409 "td_struct_ptr->STATE", &task_state
410 )) {
411 return ERROR_FAIL;
412 }
413 task_state &= MQX_TASK_STATE_MASK;
414 /* and search for defined state */
415 state_max = (sizeof(mqx_states)/sizeof(struct mqx_state));
416 for (state_index = 0; (state_index < state_max); state_index++) {
417 if (mqx_states[state_index].state == task_state) {
418 state_name = mqx_states[state_index].name;
419 break;
420 }
421 }
422
423 /* setup thread details struct */
424 rtos->thread_details[i].threadid = task_id;
425 rtos->thread_details[i].exists = true;
426 rtos->thread_details[i].display_str = NULL;
427 /* set thread name */
428 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
429 if (NULL == rtos->thread_details[i].thread_name_str)
430 return ERROR_FAIL;
431 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
432 /* set thread extra info
433 * - task state
434 * - task address
435 * - task errno
436 * calculate length as:
437 * state length + address length + errno length + formatter length
438 */
439 extra_info_length += strlen((void *)state_name) + 8 + 8 + 8;
440 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
441 if (NULL == rtos->thread_details[i].extra_info_str)
442 return ERROR_FAIL;
443 snprintf(
444 rtos->thread_details[i].extra_info_str, extra_info_length, "%s : 0x%"PRIx32 " : %" PRIu32,
445 state_name, task_addr, task_errno
446 );
447 /* set active thread */
448 if (active_td_addr == task_addr)
449 rtos->current_thread = task_id;
450 }
451 return ERROR_OK;
452 }
453
454 /*
455 * API function, get info of selected thread
456 */
457 static int mqx_get_thread_reg_list(
458 struct rtos *rtos,
459 int64_t thread_id,
460 char **hex_reg_list
461 )
462 {
463 int64_t stack_ptr = 0;
464 uint32_t my_task_addr = 0;
465 uint32_t task_queue_addr = 0;
466 uint32_t task_queue_size = 0;
467 uint32_t kernel_data_addr = 0;
468
469 *hex_reg_list = NULL;
470 if (thread_id == 0) {
471 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
472 return ERROR_FAIL;
473 }
474 if (ERROR_OK != mqx_is_scheduler_running(rtos))
475 return ERROR_FAIL;
476 /* get kernel_data symbol */
477 if (ERROR_OK != mqx_get_symbol(
478 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
479 )) {
480 return ERROR_FAIL;
481 }
482 /* read kernel_data */
483 if (ERROR_OK != mqx_get_member(
484 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
485 )) {
486 return ERROR_FAIL;
487 }
488 /* get task queue address */
489 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
490 /* get task queue size */
491 if (ERROR_OK != mqx_get_member(
492 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
493 "kernel_data->TD_LIST.SIZE", &task_queue_size
494 )) {
495 return ERROR_FAIL;
496 }
497 /* search for taskid */
498 for (
499 uint32_t i = 0, taskpool_addr = task_queue_addr;
500 i < (uint32_t)rtos->thread_count;
501 i++
502 ) {
503 uint32_t tmp_address = 0, task_addr = 0;
504 uint32_t task_id = 0;
505 /* set current taskpool address */
506 tmp_address = taskpool_addr;
507 if (ERROR_OK != mqx_get_member(
508 rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
509 "td_struct_ptr->NEXT", &taskpool_addr
510 )) {
511 return ERROR_FAIL;
512 }
513 /* get task address from taskpool */
514 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
515 /* get value of td_struct->TASK_ID */
516 if (ERROR_OK != mqx_get_member(
517 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
518 "td_struct_ptr->TASK_ID", &task_id
519 )) {
520 return ERROR_FAIL;
521 }
522 /* found taskid, break */
523 if (task_id == thread_id) {
524 my_task_addr = task_addr;
525 break;
526 }
527 }
528 if (!my_task_addr) {
529 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
530 return ERROR_FAIL;
531 }
532 /* get task stack head address */
533 if (ERROR_OK != mqx_get_member(
534 rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr
535 )) {
536 return ERROR_FAIL;
537 }
538 return rtos_generic_stack_read(
539 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
540 );
541 }
542
543 /* API function, export list of required symbols */
544 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
545 {
546 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t));
547 if (NULL == *symbol_list)
548 return ERROR_FAIL;
549 /* export required symbols */
550 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
551 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
552 return ERROR_OK;
553 }
554
555 struct rtos_type mqx_rtos = {
556 .name = "mqx",
557 .detect_rtos = mqx_detect_rtos,
558 .create = mqx_create,
559 .update_threads = mqx_update_threads,
560 .get_thread_reg_list = mqx_get_thread_reg_list,
561 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
562 };

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)