doc: document noinit command
[openocd.git] / src / rtos / mqx.c
blob754470e3c6e2cb10e12f8a21a5fc173419618bac
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 ***************************************************************************/
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
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"
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)
50 /* types */
51 enum mqx_symbols {
52 MQX_VAL_MQX_KERNEL_DATA,
53 MQX_VAL_MQX_INIT_STRUCT,
56 enum mqx_arch {
57 mqx_arch_cortexm,
60 struct mqx_params {
61 const char *target_name;
62 const enum mqx_arch target_arch;
63 const struct rtos_register_stacking *stacking_info;
66 struct mqx_state {
67 uint32_t state;
68 char *name;
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" },
90 static const char * const mqx_symbol_list[] = {
91 "_mqx_kernel_data",
92 "MQX_init_struct",
93 NULL
96 static const struct mqx_params mqx_params_list[] = {
97 { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking },
101 * Perform simple address check to avoid bus fault.
103 static int mqx_valid_address_check(
104 struct rtos *rtos,
105 uint32_t address
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;
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)
119 return ERROR_OK;
121 return ERROR_FAIL;
123 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname);
124 return ERROR_FAIL;
128 * Wrapper of 'target_read_buffer' fn.
129 * Include address check.
131 static int mqx_target_read_buffer(
132 struct target *target,
133 uint32_t address,
134 uint32_t size,
135 uint8_t *buffer
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;
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;
148 return ERROR_OK;
152 * Get symbol address if present
154 static int mqx_get_symbol(
155 struct rtos *rtos,
156 enum mqx_symbols symbol,
157 void *result
160 /* TODO: additional check ?? */
161 (*(int *)result) = (uint32_t)rtos->symbols[symbol].address;
162 return ERROR_OK;
166 * Get value of struct member by passing
167 * member offset, width and name (debug purpose)
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
178 int status = ERROR_FAIL;
179 status = mqx_target_read_buffer(
180 rtos->target, base_address + member_offset, member_width, result
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;
189 * Check whether scheduler started
191 static int mqx_is_scheduler_running(
192 struct rtos *rtos
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;
201 /* get '_mqx_kernel_data' symbol */
202 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK)
203 return ERROR_FAIL;
205 /* get '_mqx_kernel_data' */
206 if (mqx_get_member(rtos, kernel_data_symbol, 0, 4,
207 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
208 return ERROR_FAIL;
210 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
211 if (kernel_data_addr == 0 || kernel_data_addr == (uint32_t)(-1))
212 return ERROR_FAIL;
213 /* get kernel_data->ADDRESSING_CAPABILITY */
214 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4,
215 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value) != ERROR_OK)
216 return ERROR_FAIL;
218 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
219 it suppose to be set to value 8 */
220 if (capability_value != 8) {
221 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
222 return ERROR_FAIL;
224 /* get active ptr */
225 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
226 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
227 return ERROR_FAIL;
229 /* active task is system task, scheduler has not not run yet */
230 system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK;
231 if (active_td_addr == system_td_addr) {
232 LOG_WARNING("MQX RTOS - scheduler does not run");
233 return ERROR_FAIL;
235 return ERROR_OK;
239 * API function, return true if MQX is present
241 static bool mqx_detect_rtos(
242 struct target *target
245 if (
246 (target->rtos->symbols) &&
247 (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0)
249 return true;
251 return false;
255 * API function, pass MQX extra info to context data
257 static int mqx_create(
258 struct target *target
261 /* check target name against supported architectures */
262 for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) {
263 if (strcmp(mqx_params_list[i].target_name, target->type->name) == 0) {
264 target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
265 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
266 return 0;
269 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
270 return -1;
274 * API function, update list of threads
276 static int mqx_update_threads(
277 struct rtos *rtos
280 uint32_t task_queue_addr = 0;
281 uint32_t kernel_data_addr = 0;
282 uint16_t task_queue_size = 0;
283 uint32_t active_td_addr = 0;
285 if (!rtos->rtos_specific_params)
286 return -3;
288 if (!rtos->symbols)
289 return -4;
291 /* clear old data */
292 rtos_free_threadlist(rtos);
293 /* check scheduler */
294 if (mqx_is_scheduler_running(rtos) != ERROR_OK)
295 return ERROR_FAIL;
296 /* get kernel_data symbol */
297 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
298 return ERROR_FAIL;
300 /* read kernel_data */
301 if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
302 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
303 return ERROR_FAIL;
305 /* get task queue address */
306 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
307 /* get task queue size */
308 if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
309 "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
310 return ERROR_FAIL;
312 /* get active ptr */
313 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
314 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
315 return ERROR_FAIL;
317 /* setup threads info */
318 rtos->thread_count = task_queue_size;
319 rtos->current_thread = 0;
320 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
321 if (!rtos->thread_details)
322 return ERROR_FAIL;
324 /* loop over each task and setup thread details,
325 the current_taskpool_addr is set to queue head
326 NOTE: debugging functions task create/destroy
327 might cause to show invalid data.
329 for (
330 uint32_t i = 0, taskpool_addr = task_queue_addr;
331 i < (uint32_t)rtos->thread_count;
334 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
335 uint32_t task_addr = 0, task_template = 0, task_state = 0;
336 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
337 uint32_t state_index = 0;
338 uint32_t extra_info_length = 0;
339 char *state_name = "Unknown";
341 /* set current taskpool address */
342 if (mqx_get_member(rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
343 "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
344 return ERROR_FAIL;
346 /* get task address from taskpool */
347 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
348 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
349 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
350 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template) != ERROR_OK)
351 return ERROR_FAIL;
353 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
354 if (mqx_get_member(rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
355 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr) != ERROR_OK)
356 return ERROR_FAIL;
358 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
359 if (mqx_get_member(rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
360 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name) != ERROR_OK)
361 return ERROR_FAIL;
363 /* always terminate last character by force,
364 otherwise openocd might fail if task_name
365 has corrupted data */
366 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
367 /* get value of 'td_struct_ptr->TASK_ID' */
368 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
369 "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
370 return ERROR_FAIL;
372 /* get task errno */
373 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
374 "td_struct_ptr->TASK_ERROR_CODE", &task_errno) != ERROR_OK)
375 return ERROR_FAIL;
377 /* get value of 'td_struct_ptr->STATE' */
378 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
379 "td_struct_ptr->STATE", &task_state) != ERROR_OK)
380 return ERROR_FAIL;
382 task_state &= MQX_TASK_STATE_MASK;
383 /* and search for defined state */
384 for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) {
385 if (mqx_states[state_index].state == task_state) {
386 state_name = mqx_states[state_index].name;
387 break;
391 /* setup thread details struct */
392 rtos->thread_details[i].threadid = task_id;
393 rtos->thread_details[i].exists = true;
394 /* set thread name */
395 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
396 if (!rtos->thread_details[i].thread_name_str)
397 return ERROR_FAIL;
398 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
399 /* set thread extra info
400 * - task state
401 * - task address
402 * - task errno
403 * calculate length as:
404 * state length + address length + errno length + formatter length
406 extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
407 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
408 if (!rtos->thread_details[i].extra_info_str)
409 return ERROR_FAIL;
410 snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
411 "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
412 state_name, task_addr, task_errno
414 /* set active thread */
415 if (active_td_addr == task_addr)
416 rtos->current_thread = task_id;
418 return ERROR_OK;
422 * API function, get info of selected thread
424 static int mqx_get_thread_reg_list(
425 struct rtos *rtos,
426 int64_t thread_id,
427 struct rtos_reg **reg_list,
428 int *num_regs
431 int64_t stack_ptr = 0;
432 uint32_t my_task_addr = 0;
433 uint32_t task_queue_addr = 0;
434 uint32_t task_queue_size = 0;
435 uint32_t kernel_data_addr = 0;
437 if (thread_id == 0) {
438 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
439 return ERROR_FAIL;
441 if (mqx_is_scheduler_running(rtos) != ERROR_OK)
442 return ERROR_FAIL;
443 /* get kernel_data symbol */
444 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
445 return ERROR_FAIL;
447 /* read kernel_data */
448 if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
449 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
450 return ERROR_FAIL;
452 /* get task queue address */
453 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
454 /* get task queue size */
455 if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
456 "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
457 return ERROR_FAIL;
459 /* search for taskid */
460 for (
461 uint32_t i = 0, taskpool_addr = task_queue_addr;
462 i < (uint32_t)rtos->thread_count;
465 uint32_t tmp_address = 0, task_addr = 0;
466 uint32_t task_id = 0;
467 /* set current taskpool address */
468 tmp_address = taskpool_addr;
469 if (mqx_get_member(rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
470 "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
471 return ERROR_FAIL;
473 /* get task address from taskpool */
474 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
475 /* get value of td_struct->TASK_ID */
476 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
477 "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
478 return ERROR_FAIL;
480 /* found taskid, break */
481 if (task_id == thread_id) {
482 my_task_addr = task_addr;
483 break;
486 if (!my_task_addr) {
487 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
488 return ERROR_FAIL;
490 /* get task stack head address */
491 if (mqx_get_member(rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4,
492 "task->STACK_PTR", &stack_ptr) != ERROR_OK)
493 return ERROR_FAIL;
495 return rtos_generic_stack_read(
496 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
500 /* API function, export list of required symbols */
501 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
503 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem));
504 if (!*symbol_list)
505 return ERROR_FAIL;
506 /* export required symbols */
507 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
508 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
509 return ERROR_OK;
512 struct rtos_type mqx_rtos = {
513 .name = "mqx",
514 .detect_rtos = mqx_detect_rtos,
515 .create = mqx_create,
516 .update_threads = mqx_update_threads,
517 .get_thread_reg_list = mqx_get_thread_reg_list,
518 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,