openocd: use macro ARRAY_SIZE()
[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 suppose 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 true if MQX is present
248 */
249 static bool 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 true;
258 }
259 return false;
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 for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) {
271 if (0 == strcmp(mqx_params_list[i].target_name, target->type->name)) {
272 target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
273 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
274 return 0;
275 }
276 }
277 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
278 return -1;
279 }
280
281 /*
282 * API function, update list of threads
283 */
284 static int mqx_update_threads(
285 struct rtos *rtos
286 )
287 {
288 uint32_t task_queue_addr = 0;
289 uint32_t kernel_data_addr = 0;
290 uint16_t task_queue_size = 0;
291 uint32_t active_td_addr = 0;
292
293 if (!rtos->rtos_specific_params)
294 return -3;
295
296 if (!rtos->symbols)
297 return -4;
298
299 /* clear old data */
300 rtos_free_threadlist(rtos);
301 /* check scheduler */
302 if (ERROR_OK != mqx_is_scheduler_running(rtos))
303 return ERROR_FAIL;
304 /* get kernel_data symbol */
305 if (ERROR_OK != mqx_get_symbol(
306 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
307 )) {
308 return ERROR_FAIL;
309 }
310 /* read kernel_data */
311 if (ERROR_OK != mqx_get_member(
312 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
313 )) {
314 return ERROR_FAIL;
315 }
316 /* get task queue address */
317 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
318 /* get task queue size */
319 if (ERROR_OK != mqx_get_member(
320 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
321 "kernel_data->TD_LIST.SIZE", &task_queue_size
322 )) {
323 return ERROR_FAIL;
324 }
325 /* get active ptr */
326 if (ERROR_OK != mqx_get_member(
327 rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
328 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr
329 )) {
330 return ERROR_FAIL;
331 }
332
333 /* setup threads info */
334 rtos->thread_count = task_queue_size;
335 rtos->current_thread = 0;
336 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
337 if (NULL == rtos->thread_details)
338 return ERROR_FAIL;
339
340 /* loop over each task and setup thread details,
341 the current_taskpool_addr is set to queue head
342 NOTE: debugging functions task create/destroy
343 might cause to show invalid data.
344 */
345 for (
346 uint32_t i = 0, taskpool_addr = task_queue_addr;
347 i < (uint32_t)rtos->thread_count;
348 i++
349 ) {
350 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
351 uint32_t task_addr = 0, task_template = 0, task_state = 0;
352 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
353 uint32_t state_index = 0;
354 uint32_t extra_info_length = 0;
355 char *state_name = "Unknown";
356
357 /* set current taskpool address */
358 if (ERROR_OK != mqx_get_member(
359 rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
360 "td_struct_ptr->NEXT", &taskpool_addr
361 )) {
362 return ERROR_FAIL;
363 }
364 /* get task address from taskpool */
365 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
366 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
367 if (ERROR_OK != mqx_get_member(
368 rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
369 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template
370 )) {
371 return ERROR_FAIL;
372 }
373 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
374 if (ERROR_OK != mqx_get_member(
375 rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
376 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr
377 )) {
378 return ERROR_FAIL;
379 }
380 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
381 if (ERROR_OK != mqx_get_member(
382 rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
383 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name
384 )) {
385 return ERROR_FAIL;
386 }
387 /* always terminate last character by force,
388 otherwise openocd might fail if task_name
389 has corrupted data */
390 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
391 /* get value of 'td_struct_ptr->TASK_ID' */
392 if (ERROR_OK != mqx_get_member(
393 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
394 "td_struct_ptr->TASK_ID", &task_id
395 )) {
396 return ERROR_FAIL;
397 }
398 /* get task errno */
399 if (ERROR_OK != mqx_get_member(
400 rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
401 "td_struct_ptr->TASK_ERROR_CODE", &task_errno
402 )) {
403 return ERROR_FAIL;
404 }
405 /* get value of 'td_struct_ptr->STATE' */
406 if (ERROR_OK != mqx_get_member(
407 rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
408 "td_struct_ptr->STATE", &task_state
409 )) {
410 return ERROR_FAIL;
411 }
412 task_state &= MQX_TASK_STATE_MASK;
413 /* and search for defined state */
414 for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) {
415 if (mqx_states[state_index].state == task_state) {
416 state_name = mqx_states[state_index].name;
417 break;
418 }
419 }
420
421 /* setup thread details struct */
422 rtos->thread_details[i].threadid = task_id;
423 rtos->thread_details[i].exists = true;
424 /* set thread name */
425 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
426 if (NULL == rtos->thread_details[i].thread_name_str)
427 return ERROR_FAIL;
428 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
429 /* set thread extra info
430 * - task state
431 * - task address
432 * - task errno
433 * calculate length as:
434 * state length + address length + errno length + formatter length
435 */
436 extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
437 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
438 if (NULL == rtos->thread_details[i].extra_info_str)
439 return ERROR_FAIL;
440 snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
441 "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
442 state_name, task_addr, task_errno
443 );
444 /* set active thread */
445 if (active_td_addr == task_addr)
446 rtos->current_thread = task_id;
447 }
448 return ERROR_OK;
449 }
450
451 /*
452 * API function, get info of selected thread
453 */
454 static int mqx_get_thread_reg_list(
455 struct rtos *rtos,
456 int64_t thread_id,
457 struct rtos_reg **reg_list,
458 int *num_regs
459 )
460 {
461 int64_t stack_ptr = 0;
462 uint32_t my_task_addr = 0;
463 uint32_t task_queue_addr = 0;
464 uint32_t task_queue_size = 0;
465 uint32_t kernel_data_addr = 0;
466
467 if (thread_id == 0) {
468 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
469 return ERROR_FAIL;
470 }
471 if (ERROR_OK != mqx_is_scheduler_running(rtos))
472 return ERROR_FAIL;
473 /* get kernel_data symbol */
474 if (ERROR_OK != mqx_get_symbol(
475 rtos, mqx_VAL_mqx_kernel_data, &kernel_data_addr
476 )) {
477 return ERROR_FAIL;
478 }
479 /* read kernel_data */
480 if (ERROR_OK != mqx_get_member(
481 rtos, kernel_data_addr, 0, 4, "_mqx_kernel_data", &kernel_data_addr
482 )) {
483 return ERROR_FAIL;
484 }
485 /* get task queue address */
486 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
487 /* get task queue size */
488 if (ERROR_OK != mqx_get_member(
489 rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
490 "kernel_data->TD_LIST.SIZE", &task_queue_size
491 )) {
492 return ERROR_FAIL;
493 }
494 /* search for taskid */
495 for (
496 uint32_t i = 0, taskpool_addr = task_queue_addr;
497 i < (uint32_t)rtos->thread_count;
498 i++
499 ) {
500 uint32_t tmp_address = 0, task_addr = 0;
501 uint32_t task_id = 0;
502 /* set current taskpool address */
503 tmp_address = taskpool_addr;
504 if (ERROR_OK != mqx_get_member(
505 rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
506 "td_struct_ptr->NEXT", &taskpool_addr
507 )) {
508 return ERROR_FAIL;
509 }
510 /* get task address from taskpool */
511 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
512 /* get value of td_struct->TASK_ID */
513 if (ERROR_OK != mqx_get_member(
514 rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
515 "td_struct_ptr->TASK_ID", &task_id
516 )) {
517 return ERROR_FAIL;
518 }
519 /* found taskid, break */
520 if (task_id == thread_id) {
521 my_task_addr = task_addr;
522 break;
523 }
524 }
525 if (!my_task_addr) {
526 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
527 return ERROR_FAIL;
528 }
529 /* get task stack head address */
530 if (ERROR_OK != mqx_get_member(
531 rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4, "task->STACK_PTR", &stack_ptr
532 )) {
533 return ERROR_FAIL;
534 }
535 return rtos_generic_stack_read(
536 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
537 );
538 }
539
540 /* API function, export list of required symbols */
541 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
542 {
543 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem));
544 if (NULL == *symbol_list)
545 return ERROR_FAIL;
546 /* export required symbols */
547 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
548 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
549 return ERROR_OK;
550 }
551
552 struct rtos_type mqx_rtos = {
553 .name = "mqx",
554 .detect_rtos = mqx_detect_rtos,
555 .create = mqx_create,
556 .update_threads = mqx_update_threads,
557 .get_thread_reg_list = mqx_get_thread_reg_list,
558 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
559 };

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)