openocd: fix SPDX tag format for files .c
[openocd.git] / src / rtos / mqx.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2014 by Marian Cingel *
5 * cingel.marian@gmail.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdint.h>
13 #include <helper/time_support.h>
14 #include <jtag/jtag.h>
15 #include "target/target.h"
16 #include "target/target_type.h"
17 #include "rtos.h"
18 #include "helper/log.h"
19 #include "helper/types.h"
20 #include "rtos_mqx_stackings.h"
21
22 /* constants */
23 #define MQX_THREAD_NAME_LENGTH (255)
24 #define MQX_KERNEL_OFFSET_TDLIST (0x0108)
25 #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050)
26 #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C)
27 #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000)
28 #define MQX_QUEUE_OFFSET_SIZE (0x0008)
29 #define MQX_TASK_OFFSET_STATE (0x0008)
30 #define MQX_TASK_OFFSET_ID (0x000c)
31 #define MQX_TASK_OFFSET_TEMPLATE (0x0068)
32 #define MQX_TASK_OFFSET_STACK (0x0014)
33 #define MQX_TASK_OFFSET_TDLIST (0x006C)
34 #define MQX_TASK_OFFSET_NEXT (0x0000)
35 #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010)
36 #define MQX_TASK_OFFSET_ERROR_CODE (0x005C)
37 #define MQX_TASK_STATE_MASK (0xFFF)
38
39 /* types */
40 enum mqx_symbols {
41 MQX_VAL_MQX_KERNEL_DATA,
42 MQX_VAL_MQX_INIT_STRUCT,
43 };
44
45 enum mqx_arch {
46 mqx_arch_cortexm,
47 };
48
49 struct mqx_params {
50 const char *target_name;
51 const enum mqx_arch target_arch;
52 const struct rtos_register_stacking *stacking_info;
53 };
54
55 struct mqx_state {
56 uint32_t state;
57 char *name;
58 };
59
60 /* local data */
61 static const struct mqx_state mqx_states[] = {
62 { 0x0002, "READY" },
63 { 0x0003, "BLOCKED" },
64 { 0x0005, "RCV_SPECIFIC_BLOCKED" },
65 { 0x0007, "RCV_ANY_BLOCKED" },
66 { 0x0009, "DYING" },
67 { 0x000B, "UNHANDLED_INT_BLOCKED" },
68 { 0x000D, "SEND_BLOCKED" },
69 { 0x000F, "BREAKPOINT_BLOCKED" },
70 { 0x0211, "IO_BLOCKED" },
71 { 0x0021, "SEM_BLOCKED" },
72 { 0x0223, "MUTEX_BLOCKED" },
73 { 0x0025, "EVENT_BLOCKED" },
74 { 0x0229, "TASK_QUEUE_BLOCKED" },
75 { 0x042B, "LWSEM_BLOCKED" },
76 { 0x042D, "LWEVENT_BLOCKED" },
77 };
78
79 static const char * const mqx_symbol_list[] = {
80 "_mqx_kernel_data",
81 "MQX_init_struct",
82 NULL
83 };
84
85 static const struct mqx_params mqx_params_list[] = {
86 { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking },
87 };
88
89 /*
90 * Perform simple address check to avoid bus fault.
91 */
92 static int mqx_valid_address_check(
93 struct rtos *rtos,
94 uint32_t address
95 )
96 {
97 enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch;
98 const char *targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name;
99
100 /* Cortex-M address range */
101 if (arch_type == mqx_arch_cortexm) {
102 if (
103 /* code and sram area */
104 (address && address <= 0x3FFFFFFFu) ||
105 /* external ram area*/
106 (address >= 0x6000000u && address <= 0x9FFFFFFFu)
107 ) {
108 return ERROR_OK;
109 }
110 return ERROR_FAIL;
111 }
112 LOG_ERROR("MQX RTOS - unknown architecture %s", targetname);
113 return ERROR_FAIL;
114 }
115
116 /*
117 * Wrapper of 'target_read_buffer' fn.
118 * Include address check.
119 */
120 static int mqx_target_read_buffer(
121 struct target *target,
122 uint32_t address,
123 uint32_t size,
124 uint8_t *buffer
125 )
126 {
127 int status = mqx_valid_address_check(target->rtos, address);
128 if (status != ERROR_OK) {
129 LOG_WARNING("MQX RTOS - target address 0x%" PRIx32 " is not allowed to read", address);
130 return status;
131 }
132 status = target_read_buffer(target, address, size, buffer);
133 if (status != ERROR_OK) {
134 LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32" failed", address);
135 return status;
136 }
137 return ERROR_OK;
138 }
139
140 /*
141 * Get symbol address if present
142 */
143 static int mqx_get_symbol(
144 struct rtos *rtos,
145 enum mqx_symbols symbol,
146 void *result
147 )
148 {
149 /* TODO: additional check ?? */
150 (*(int *)result) = (uint32_t)rtos->symbols[symbol].address;
151 return ERROR_OK;
152 }
153
154 /*
155 * Get value of struct member by passing
156 * member offset, width and name (debug purpose)
157 */
158 static int mqx_get_member(
159 struct rtos *rtos,
160 const uint32_t base_address,
161 int32_t member_offset,
162 int32_t member_width,
163 const char *member_name,
164 void *result
165 )
166 {
167 int status = ERROR_FAIL;
168 status = mqx_target_read_buffer(
169 rtos->target, base_address + member_offset, member_width, result
170 );
171 if (status != ERROR_OK)
172 LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32,
173 member_name, (uint32_t)(base_address + member_offset));
174 return status;
175 }
176
177 /*
178 * Check whether scheduler started
179 */
180 static int mqx_is_scheduler_running(
181 struct rtos *rtos
182 )
183 {
184 uint32_t kernel_data_symbol = 0;
185 uint32_t kernel_data_addr = 0;
186 uint32_t system_td_addr = 0;
187 uint32_t active_td_addr = 0;
188 uint32_t capability_value = 0;
189
190 /* get '_mqx_kernel_data' symbol */
191 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK)
192 return ERROR_FAIL;
193
194 /* get '_mqx_kernel_data' */
195 if (mqx_get_member(rtos, kernel_data_symbol, 0, 4,
196 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
197 return ERROR_FAIL;
198
199 /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
200 if (kernel_data_addr == 0 || kernel_data_addr == (uint32_t)(-1))
201 return ERROR_FAIL;
202 /* get kernel_data->ADDRESSING_CAPABILITY */
203 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4,
204 "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value) != ERROR_OK)
205 return ERROR_FAIL;
206
207 /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
208 it suppose to be set to value 8 */
209 if (capability_value != 8) {
210 LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
211 return ERROR_FAIL;
212 }
213 /* get active ptr */
214 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
215 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
216 return ERROR_FAIL;
217
218 /* active task is system task, scheduler has not not run yet */
219 system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK;
220 if (active_td_addr == system_td_addr) {
221 LOG_WARNING("MQX RTOS - scheduler does not run");
222 return ERROR_FAIL;
223 }
224 return ERROR_OK;
225 }
226
227 /*
228 * API function, return true if MQX is present
229 */
230 static bool mqx_detect_rtos(
231 struct target *target
232 )
233 {
234 if (
235 (target->rtos->symbols) &&
236 (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0)
237 ) {
238 return true;
239 }
240 return false;
241 }
242
243 /*
244 * API function, pass MQX extra info to context data
245 */
246 static int mqx_create(
247 struct target *target
248 )
249 {
250 /* check target name against supported architectures */
251 for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) {
252 if (strcmp(mqx_params_list[i].target_name, target->type->name) == 0) {
253 target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
254 /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
255 return 0;
256 }
257 }
258 LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
259 return -1;
260 }
261
262 /*
263 * API function, update list of threads
264 */
265 static int mqx_update_threads(
266 struct rtos *rtos
267 )
268 {
269 uint32_t task_queue_addr = 0;
270 uint32_t kernel_data_addr = 0;
271 uint16_t task_queue_size = 0;
272 uint32_t active_td_addr = 0;
273
274 if (!rtos->rtos_specific_params)
275 return -3;
276
277 if (!rtos->symbols)
278 return -4;
279
280 /* clear old data */
281 rtos_free_threadlist(rtos);
282 /* check scheduler */
283 if (mqx_is_scheduler_running(rtos) != ERROR_OK)
284 return ERROR_FAIL;
285 /* get kernel_data symbol */
286 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
287 return ERROR_FAIL;
288
289 /* read kernel_data */
290 if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
291 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
292 return ERROR_FAIL;
293
294 /* get task queue address */
295 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
296 /* get task queue size */
297 if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
298 "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
299 return ERROR_FAIL;
300
301 /* get active ptr */
302 if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
303 "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
304 return ERROR_FAIL;
305
306 /* setup threads info */
307 rtos->thread_count = task_queue_size;
308 rtos->current_thread = 0;
309 rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
310 if (!rtos->thread_details)
311 return ERROR_FAIL;
312
313 /* loop over each task and setup thread details,
314 the current_taskpool_addr is set to queue head
315 NOTE: debugging functions task create/destroy
316 might cause to show invalid data.
317 */
318 for (
319 uint32_t i = 0, taskpool_addr = task_queue_addr;
320 i < (uint32_t)rtos->thread_count;
321 i++
322 ) {
323 uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
324 uint32_t task_addr = 0, task_template = 0, task_state = 0;
325 uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
326 uint32_t state_index = 0;
327 uint32_t extra_info_length = 0;
328 char *state_name = "Unknown";
329
330 /* set current taskpool address */
331 if (mqx_get_member(rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
332 "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
333 return ERROR_FAIL;
334
335 /* get task address from taskpool */
336 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
337 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
338 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
339 "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template) != ERROR_OK)
340 return ERROR_FAIL;
341
342 /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
343 if (mqx_get_member(rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
344 "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr) != ERROR_OK)
345 return ERROR_FAIL;
346
347 /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
348 if (mqx_get_member(rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
349 "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name) != ERROR_OK)
350 return ERROR_FAIL;
351
352 /* always terminate last character by force,
353 otherwise openocd might fail if task_name
354 has corrupted data */
355 task_name[MQX_THREAD_NAME_LENGTH] = '\0';
356 /* get value of 'td_struct_ptr->TASK_ID' */
357 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
358 "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
359 return ERROR_FAIL;
360
361 /* get task errno */
362 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
363 "td_struct_ptr->TASK_ERROR_CODE", &task_errno) != ERROR_OK)
364 return ERROR_FAIL;
365
366 /* get value of 'td_struct_ptr->STATE' */
367 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
368 "td_struct_ptr->STATE", &task_state) != ERROR_OK)
369 return ERROR_FAIL;
370
371 task_state &= MQX_TASK_STATE_MASK;
372 /* and search for defined state */
373 for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) {
374 if (mqx_states[state_index].state == task_state) {
375 state_name = mqx_states[state_index].name;
376 break;
377 }
378 }
379
380 /* setup thread details struct */
381 rtos->thread_details[i].threadid = task_id;
382 rtos->thread_details[i].exists = true;
383 /* set thread name */
384 rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
385 if (!rtos->thread_details[i].thread_name_str)
386 return ERROR_FAIL;
387 strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
388 /* set thread extra info
389 * - task state
390 * - task address
391 * - task errno
392 * calculate length as:
393 * state length + address length + errno length + formatter length
394 */
395 extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
396 rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
397 if (!rtos->thread_details[i].extra_info_str)
398 return ERROR_FAIL;
399 snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
400 "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
401 state_name, task_addr, task_errno
402 );
403 /* set active thread */
404 if (active_td_addr == task_addr)
405 rtos->current_thread = task_id;
406 }
407 return ERROR_OK;
408 }
409
410 /*
411 * API function, get info of selected thread
412 */
413 static int mqx_get_thread_reg_list(
414 struct rtos *rtos,
415 int64_t thread_id,
416 struct rtos_reg **reg_list,
417 int *num_regs
418 )
419 {
420 int64_t stack_ptr = 0;
421 uint32_t my_task_addr = 0;
422 uint32_t task_queue_addr = 0;
423 uint32_t task_queue_size = 0;
424 uint32_t kernel_data_addr = 0;
425
426 if (thread_id == 0) {
427 LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
428 return ERROR_FAIL;
429 }
430 if (mqx_is_scheduler_running(rtos) != ERROR_OK)
431 return ERROR_FAIL;
432 /* get kernel_data symbol */
433 if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
434 return ERROR_FAIL;
435
436 /* read kernel_data */
437 if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
438 "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
439 return ERROR_FAIL;
440
441 /* get task queue address */
442 task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
443 /* get task queue size */
444 if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
445 "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
446 return ERROR_FAIL;
447
448 /* search for taskid */
449 for (
450 uint32_t i = 0, taskpool_addr = task_queue_addr;
451 i < (uint32_t)rtos->thread_count;
452 i++
453 ) {
454 uint32_t tmp_address = 0, task_addr = 0;
455 uint32_t task_id = 0;
456 /* set current taskpool address */
457 tmp_address = taskpool_addr;
458 if (mqx_get_member(rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
459 "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
460 return ERROR_FAIL;
461
462 /* get task address from taskpool */
463 task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
464 /* get value of td_struct->TASK_ID */
465 if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
466 "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
467 return ERROR_FAIL;
468
469 /* found taskid, break */
470 if (task_id == thread_id) {
471 my_task_addr = task_addr;
472 break;
473 }
474 }
475 if (!my_task_addr) {
476 LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
477 return ERROR_FAIL;
478 }
479 /* get task stack head address */
480 if (mqx_get_member(rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4,
481 "task->STACK_PTR", &stack_ptr) != ERROR_OK)
482 return ERROR_FAIL;
483
484 return rtos_generic_stack_read(
485 rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
486 );
487 }
488
489 /* API function, export list of required symbols */
490 static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
491 {
492 *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem));
493 if (!*symbol_list)
494 return ERROR_FAIL;
495 /* export required symbols */
496 for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
497 (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
498 return ERROR_OK;
499 }
500
501 struct rtos_type mqx_rtos = {
502 .name = "mqx",
503 .detect_rtos = mqx_detect_rtos,
504 .create = mqx_create,
505 .update_threads = mqx_update_threads,
506 .get_thread_reg_list = mqx_get_thread_reg_list,
507 .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
508 };

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)