jtag: linuxgpiod: drop extra parenthesis
[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 (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK)
203 return ERROR_FAIL;
204
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;
209
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;
217
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;
223 }
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;
228
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;
234 }
235 return ERROR_OK;
236 }
237
238 /*
239 * API function, return true if MQX is present
240 */
241 static bool mqx_detect_rtos(
242 struct target *target
243 )
244 {
245 if (
246 (target->rtos->symbols) &&
247 (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0)
248 ) {
249 return true;
250 }
251 return false;
252 }
253
254 /*
255 * API function, pass MQX extra info to context data
256 */
257 static int mqx_create(
258 struct target *target
259 )
260 {
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;
267 }
268 }
269 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
270 return -1;
271 }
272
273 /*
274 * API function, update list of threads
275 */
276 static int mqx_update_threads(
277 struct rtos *rtos
278 )
279 {
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;
284
285 if (!rtos->rtos_specific_params)
286 return -3;
287
288 if (!rtos->symbols)
289 return -4;
290
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;
299
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;
304
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;
311
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;
316
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;
323
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.
328 */
329 for (
330 uint32_t i = 0, taskpool_addr = task_queue_addr;
331 i < (uint32_t)rtos->thread_count;
332 i++
333 ) {
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";
340
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;
345
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;
352
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;
357
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;
362
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;
371
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;
376
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;
381
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;
388 }
389 }
390
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
405 */
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
413 );
414 /* set active thread */
415 if (active_td_addr == task_addr)
416 rtos->current_thread = task_id;
417 }
418 return ERROR_OK;
419 }
420
421 /*
422 * API function, get info of selected thread
423 */
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
429 )
430 {
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;
436
437 if (thread_id == 0) {
438 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
439 return ERROR_FAIL;
440 }
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;
446
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;
451
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;
458
459 /* search for taskid */
460 for (
461 uint32_t i = 0, taskpool_addr = task_queue_addr;
462 i < (uint32_t)rtos->thread_count;
463 i++
464 ) {
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;
472
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;
479
480 /* found taskid, break */
481 if (task_id == thread_id) {
482 my_task_addr = task_addr;
483 break;
484 }
485 }
486 if (!my_task_addr) {
487 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
488 return ERROR_FAIL;
489 }
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;
494
495 return rtos_generic_stack_read(
496 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
497 );
498 }
499
500 /* API function, export list of required symbols */
501 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
502 {
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;
510 }
511
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,
519 };

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)