gdb_server: support qXfer:threads:read packet
[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";
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 /* set thread name */
427 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
428 if (NULL == rtos->thread_details[i].thread_name_str)
429 return ERROR_FAIL;
430 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
431 /* set thread extra info
432 * - task state
433 * - task address
434 * - task errno
435 * calculate length as:
436 * state length + address length + errno length + formatter length
437 */
438 extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
439 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
440 if (NULL == rtos->thread_details[i].extra_info_str)
441 return ERROR_FAIL;
442 snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
443 "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
444 state_name, task_addr, task_errno
445 );
446 /* set active thread */
447 if (active_td_addr == task_addr)
448 rtos->current_thread = task_id;
449 }
450 return ERROR_OK;
451 }
452
453 /*
454 * API function, get info of selected thread
455 */
456 static int mqx_get_thread_reg_list(
457 struct rtos *rtos,
458 int64_t thread_id,
459 char **hex_reg_list
460 )
461 {
462 int64_t stack_ptr = 0;
463 uint32_t my_task_addr = 0;
464 uint32_t task_queue_addr = 0;
465 uint32_t task_queue_size = 0;
466 uint32_t kernel_data_addr = 0;
467
468 *hex_reg_list = NULL;
469 if (thread_id == 0) {
470 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
471 return ERROR_FAIL;
472 }
473 if (ERROR_OK != mqx_is_scheduler_running(rtos))
474 return ERROR_FAIL;
475 /* get kernel_data symbol */
476 if (ERROR_OK != mqx_get_symbol(
477 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
478 )) {
479 return ERROR_FAIL;
480 }
481 /* read kernel_data */
482 if (ERROR_OK != mqx_get_member(
483 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
484 )) {
485 return ERROR_FAIL;
486 }
487 /* get task queue address */
488 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
489 /* get task queue size */
490 if (ERROR_OK != mqx_get_member(
491 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
492 "kernel_data->TD_LIST.SIZE", &task_queue_size
493 )) {
494 return ERROR_FAIL;
495 }
496 /* search for taskid */
497 for (
498 uint32_t i = 0, taskpool_addr = task_queue_addr;
499 i < (uint32_t)rtos->thread_count;
500 i++
501 ) {
502 uint32_t tmp_address = 0, task_addr = 0;
503 uint32_t task_id = 0;
504 /* set current taskpool address */
505 tmp_address = taskpool_addr;
506 if (ERROR_OK != mqx_get_member(
507 rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
508 "td_struct_ptr->NEXT", &taskpool_addr
509 )) {
510 return ERROR_FAIL;
511 }
512 /* get task address from taskpool */
513 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
514 /* get value of td_struct->TASK_ID */
515 if (ERROR_OK != mqx_get_member(
516 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
517 "td_struct_ptr->TASK_ID", &task_id
518 )) {
519 return ERROR_FAIL;
520 }
521 /* found taskid, break */
522 if (task_id == thread_id) {
523 my_task_addr = task_addr;
524 break;
525 }
526 }
527 if (!my_task_addr) {
528 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
529 return ERROR_FAIL;
530 }
531 /* get task stack head address */
532 if (ERROR_OK != mqx_get_member(
533 rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr
534 )) {
535 return ERROR_FAIL;
536 }
537 return rtos_generic_stack_read(
538 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
539 );
540 }
541
542 /* API function, export list of required symbols */
543 static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
544 {
545 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t));
546 if (NULL == *symbol_list)
547 return ERROR_FAIL;
548 /* export required symbols */
549 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
550 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
551 return ERROR_OK;
552 }
553
554 struct rtos_type mqx_rtos = {
555 .name = "mqx",
556 .detect_rtos = mqx_detect_rtos,
557 .create = mqx_create,
558 .update_threads = mqx_update_threads,
559 .get_thread_reg_list = mqx_get_thread_reg_list,
560 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
561 };

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)