272658c8a53e265707d9894e7752995ad0670d04
[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 };