1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2017 by Intel Corporation
5 * Leandro Pereira <leandro.pereira@intel.com>
6 * Daniel Glöckner <dg@emlix.com>*
7 * Copyright (C) 2021 by Synopsys, Inc.
8 * Evgeniy Didin <didin@synopsys.com>
9 ***************************************************************************/
15 #include <helper/time_support.h>
16 #include <jtag/jtag.h>
18 #include "helper/log.h"
19 #include "helper/types.h"
21 #include "rtos_standard_stackings.h"
22 #include "target/target.h"
23 #include "target/target_type.h"
24 #include "target/armv7m.h"
25 #include "target/arc.h"
27 #define UNIMPLEMENTED 0xFFFFFFFFU
29 /* ARC specific defines */
30 #define ARC_AUX_SEC_BUILD_REG 0xdb
31 #define ARC_REG_NUM 38
33 /* ARM specific defines */
34 #define ARM_XPSR_OFFSET 28
36 struct zephyr_thread
{
37 uint32_t ptr
, next_ptr
;
39 uint32_t stack_pointer
;
53 OFFSET_T_USER_OPTIONS
,
55 OFFSET_T_STACK_POINTER
,
58 OFFSET_T_PREEMPT_FLOAT
,
63 struct zephyr_params
{
64 const char *target_name
;
66 uint8_t pointer_width
;
68 uint32_t offsets
[OFFSET_MAX
];
69 const struct rtos_register_stacking
*callee_saved_stacking
;
70 const struct rtos_register_stacking
*cpu_saved_nofp_stacking
;
71 const struct rtos_register_stacking
*cpu_saved_fp_stacking
;
72 int (*get_cpu_state
)(struct rtos
*rtos
, target_addr_t
*addr
,
73 struct zephyr_params
*params
,
74 struct rtos_reg
*callee_saved_reg_list
,
75 struct rtos_reg
**reg_list
, int *num_regs
);
78 static const struct stack_register_offset arm_callee_saved
[] = {
79 { ARMV7M_R13
, 32, 32 },
83 { ARMV7M_R7
, 12, 32 },
84 { ARMV7M_R8
, 16, 32 },
85 { ARMV7M_R9
, 20, 32 },
86 { ARMV7M_R10
, 24, 32 },
87 { ARMV7M_R11
, 28, 32 },
90 static const struct stack_register_offset arc_callee_saved
[] = {
108 static const struct rtos_register_stacking arm_callee_saved_stacking
= {
109 .stack_registers_size
= 36,
110 .stack_growth_direction
= -1,
111 .num_output_registers
= ARRAY_SIZE(arm_callee_saved
),
112 .register_offsets
= arm_callee_saved
,
115 static const struct rtos_register_stacking arc_callee_saved_stacking
= {
116 .stack_registers_size
= 64,
117 .stack_growth_direction
= -1,
118 .num_output_registers
= ARRAY_SIZE(arc_callee_saved
),
119 .register_offsets
= arc_callee_saved
,
122 static const struct stack_register_offset arm_cpu_saved
[] = {
123 { ARMV7M_R0
, 0, 32 },
124 { ARMV7M_R1
, 4, 32 },
125 { ARMV7M_R2
, 8, 32 },
126 { ARMV7M_R3
, 12, 32 },
127 { ARMV7M_R4
, -1, 32 },
128 { ARMV7M_R5
, -1, 32 },
129 { ARMV7M_R6
, -1, 32 },
130 { ARMV7M_R7
, -1, 32 },
131 { ARMV7M_R8
, -1, 32 },
132 { ARMV7M_R9
, -1, 32 },
133 { ARMV7M_R10
, -1, 32 },
134 { ARMV7M_R11
, -1, 32 },
135 { ARMV7M_R12
, 16, 32 },
136 { ARMV7M_R13
, -2, 32 },
137 { ARMV7M_R14
, 20, 32 },
138 { ARMV7M_PC
, 24, 32 },
139 { ARMV7M_XPSR
, 28, 32 },
142 static struct stack_register_offset arc_cpu_saved
[] = {
172 { ARC_ILINK
, -1, 32 },
174 { ARC_BLINK
, 0, 32 },
175 { ARC_LP_COUNT
, -1, 32 },
178 { ARC_LP_START
, -1, 32 },
179 { ARC_LP_END
, -1, 32 },
180 { ARC_STATUS32
, 4, 32 }
184 enum zephyr_symbol_values
{
186 ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
,
187 ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE
,
188 ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
,
192 static target_addr_t
zephyr_cortex_m_stack_align(struct target
*target
,
193 const uint8_t *stack_data
,
194 const struct rtos_register_stacking
*stacking
, target_addr_t stack_ptr
)
196 return rtos_cortex_m_stack_align(target
, stack_data
, stacking
,
197 stack_ptr
, ARM_XPSR_OFFSET
);
200 static const struct rtos_register_stacking arm_cpu_saved_nofp_stacking
= {
201 .stack_registers_size
= 32,
202 .stack_growth_direction
= -1,
203 .num_output_registers
= ARRAY_SIZE(arm_cpu_saved
),
204 .calculate_process_stack
= zephyr_cortex_m_stack_align
,
205 .register_offsets
= arm_cpu_saved
,
208 static const struct rtos_register_stacking arm_cpu_saved_fp_stacking
= {
209 .stack_registers_size
= 32 + 18 * 4,
210 .stack_growth_direction
= -1,
211 .num_output_registers
= ARRAY_SIZE(arm_cpu_saved
),
212 .calculate_process_stack
= zephyr_cortex_m_stack_align
,
213 .register_offsets
= arm_cpu_saved
,
216 /* stack_registers_size is 8 because besides caller registers
217 * there are only blink and Status32 registers on stack left */
218 static struct rtos_register_stacking arc_cpu_saved_stacking
= {
219 .stack_registers_size
= 8,
220 .stack_growth_direction
= -1,
221 .num_output_registers
= ARRAY_SIZE(arc_cpu_saved
),
222 .register_offsets
= arc_cpu_saved
,
225 /* ARCv2 specific implementation */
226 static int zephyr_get_arc_state(struct rtos
*rtos
, target_addr_t
*addr
,
227 struct zephyr_params
*params
,
228 struct rtos_reg
*callee_saved_reg_list
,
229 struct rtos_reg
**reg_list
, int *num_regs
)
232 uint32_t real_stack_addr
;
234 int num_callee_saved_regs
;
235 const struct rtos_register_stacking
*stacking
;
237 /* Getting real stack address from Kernel thread struct */
238 retval
= target_read_u32(rtos
->target
, *addr
, &real_stack_addr
);
239 if (retval
!= ERROR_OK
)
242 /* Getting callee registers */
243 retval
= rtos_generic_stack_read(rtos
->target
,
244 params
->callee_saved_stacking
,
245 real_stack_addr
, &callee_saved_reg_list
,
246 &num_callee_saved_regs
);
247 if (retval
!= ERROR_OK
)
250 stacking
= params
->cpu_saved_nofp_stacking
;
252 /* Getting blink and status32 registers */
253 retval
= rtos_generic_stack_read(rtos
->target
, stacking
,
254 real_stack_addr
+ num_callee_saved_regs
* 4,
256 if (retval
!= ERROR_OK
)
259 for (int i
= 0; i
< num_callee_saved_regs
; i
++)
260 buf_cpy(callee_saved_reg_list
[i
].value
,
261 (*reg_list
)[callee_saved_reg_list
[i
].number
].value
,
262 callee_saved_reg_list
[i
].size
);
264 /* The blink, sp, pc offsets in arc_cpu_saved structure may be changed,
265 * but the registers number shall not. So the next code searches the
266 * offsetst of these registers in arc_cpu_saved structure. */
267 unsigned short blink_offset
= 0, pc_offset
= 0, sp_offset
= 0;
268 for (size_t i
= 0; i
< ARRAY_SIZE(arc_cpu_saved
); i
++) {
269 if (arc_cpu_saved
[i
].number
== ARC_BLINK
)
271 if (arc_cpu_saved
[i
].number
== ARC_SP
)
273 if (arc_cpu_saved
[i
].number
== ARC_PC
)
277 if (blink_offset
== 0 || sp_offset
== 0 || pc_offset
== 0) {
278 LOG_ERROR("Basic registers offsets are missing, check <arc_cpu_saved> struct");
282 /* Put blink value into PC */
283 buf_cpy((*reg_list
)[blink_offset
].value
,
284 (*reg_list
)[pc_offset
].value
, sizeof((*reg_list
)[blink_offset
].value
));
286 /* Put address after callee/caller in SP. */
289 stack_top
= real_stack_addr
+ num_callee_saved_regs
* 4
290 + arc_cpu_saved_stacking
.stack_registers_size
;
291 buf_cpy(&stack_top
, (*reg_list
)[sp_offset
].value
, sizeof(stack_top
));
296 /* ARM Cortex-M-specific implementation */
297 static int zephyr_get_arm_state(struct rtos
*rtos
, target_addr_t
*addr
,
298 struct zephyr_params
*params
,
299 struct rtos_reg
*callee_saved_reg_list
,
300 struct rtos_reg
**reg_list
, int *num_regs
)
304 int num_callee_saved_regs
;
305 const struct rtos_register_stacking
*stacking
;
307 retval
= rtos_generic_stack_read(rtos
->target
,
308 params
->callee_saved_stacking
,
309 *addr
, &callee_saved_reg_list
,
310 &num_callee_saved_regs
);
311 if (retval
!= ERROR_OK
)
314 *addr
= target_buffer_get_u32(rtos
->target
,
315 callee_saved_reg_list
[0].value
);
317 if (params
->offsets
[OFFSET_T_PREEMPT_FLOAT
] != UNIMPLEMENTED
)
318 stacking
= params
->cpu_saved_fp_stacking
;
320 stacking
= params
->cpu_saved_nofp_stacking
;
322 retval
= rtos_generic_stack_read(rtos
->target
, stacking
, *addr
, reg_list
,
324 if (retval
!= ERROR_OK
)
327 for (int i
= 1; i
< num_callee_saved_regs
; i
++)
328 buf_cpy(callee_saved_reg_list
[i
].value
,
329 (*reg_list
)[callee_saved_reg_list
[i
].number
].value
,
330 callee_saved_reg_list
[i
].size
);
334 static struct zephyr_params zephyr_params_list
[] = {
336 .target_name
= "cortex_m",
338 .callee_saved_stacking
= &arm_callee_saved_stacking
,
339 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
340 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
341 .get_cpu_state
= &zephyr_get_arm_state
,
344 .target_name
= "cortex_r4",
346 .callee_saved_stacking
= &arm_callee_saved_stacking
,
347 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
348 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
349 .get_cpu_state
= &zephyr_get_arm_state
,
352 .target_name
= "hla_target",
354 .callee_saved_stacking
= &arm_callee_saved_stacking
,
355 .cpu_saved_nofp_stacking
= &arm_cpu_saved_nofp_stacking
,
356 .cpu_saved_fp_stacking
= &arm_cpu_saved_fp_stacking
,
357 .get_cpu_state
= &zephyr_get_arm_state
,
361 .target_name
= "arcv2",
363 .callee_saved_stacking
= &arc_callee_saved_stacking
,
364 .cpu_saved_nofp_stacking
= &arc_cpu_saved_stacking
,
365 .get_cpu_state
= &zephyr_get_arc_state
,
372 static const struct symbol_table_elem zephyr_symbol_list
[] = {
374 .symbol_name
= "_kernel",
378 .symbol_name
= "_kernel_thread_info_offsets",
382 .symbol_name
= "_kernel_thread_info_size_t_size",
386 .symbol_name
= "_kernel_thread_info_num_offsets",
394 static bool zephyr_detect_rtos(struct target
*target
)
396 if (!target
->rtos
->symbols
) {
397 LOG_INFO("Zephyr: no symbols while detecting RTOS");
401 for (enum zephyr_symbol_values symbol
= ZEPHYR_VAL__KERNEL
;
402 symbol
!= ZEPHYR_VAL_COUNT
; symbol
++) {
403 LOG_INFO("Zephyr: does it have symbol %d (%s)?", symbol
,
404 target
->rtos
->symbols
[symbol
].optional
? "optional" : "mandatory");
406 if (target
->rtos
->symbols
[symbol
].optional
)
408 if (target
->rtos
->symbols
[symbol
].address
== 0)
412 LOG_INFO("Zephyr: all mandatory symbols found");
417 static int zephyr_create(struct target
*target
)
421 name
= target_type_name(target
);
423 LOG_INFO("Zephyr: looking for target: %s", name
);
425 /* ARC specific, check if EM target has security subsystem
426 * In case of ARC_HAS_SECURE zephyr option enabled
427 * the thread stack contains blink,sec_stat,status32 register
428 * values. If ARC_HAS_SECURE is disabled, only blink and status32
429 * register values are saved on stack. */
430 if (!strcmp(name
, "arcv2")) {
432 struct arc_common
*arc
= target_to_arc(target
);
433 /* Reading SEC_BUILD bcr */
434 CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc
->jtag_info
, ARC_AUX_SEC_BUILD_REG
, &value
));
436 LOG_DEBUG("ARC EM board has security subsystem, changing offsets");
437 arc_cpu_saved
[ARC_REG_NUM
- 1].offset
= 8;
438 /* After reading callee registers in stack
439 * now blink,sec_stat,status32 registers
441 arc_cpu_saved_stacking
.stack_registers_size
= 12;
445 for (struct zephyr_params
*p
= zephyr_params_list
; p
->target_name
; p
++) {
446 if (!strcmp(p
->target_name
, name
)) {
447 LOG_INFO("Zephyr: target known, params at %p", p
);
448 target
->rtos
->rtos_specific_params
= p
;
453 LOG_ERROR("Could not find target in Zephyr compatibility list");
457 struct zephyr_array
{
462 static void zephyr_array_init(struct zephyr_array
*array
)
468 static void zephyr_array_free(struct zephyr_array
*array
)
471 zephyr_array_init(array
);
474 static void *zephyr_array_append(struct zephyr_array
*array
, size_t size
)
476 if (!(array
->elements
% 16)) {
477 void *ptr
= realloc(array
->ptr
, (array
->elements
+ 16) * size
);
480 LOG_ERROR("Out of memory");
487 return (unsigned char *)array
->ptr
+ (array
->elements
++) * size
;
490 static void *zephyr_array_detach_ptr(struct zephyr_array
*array
)
492 void *ptr
= array
->ptr
;
494 zephyr_array_init(array
);
499 static uint32_t zephyr_kptr(const struct rtos
*rtos
, enum zephyr_offsets off
)
501 const struct zephyr_params
*params
= rtos
->rtos_specific_params
;
503 return rtos
->symbols
[ZEPHYR_VAL__KERNEL
].address
+ params
->offsets
[off
];
506 static int zephyr_fetch_thread(const struct rtos
*rtos
,
507 struct zephyr_thread
*thread
, uint32_t ptr
)
509 const struct zephyr_params
*param
= rtos
->rtos_specific_params
;
514 retval
= target_read_u32(rtos
->target
, ptr
+ param
->offsets
[OFFSET_T_ENTRY
],
516 if (retval
!= ERROR_OK
)
519 retval
= target_read_u32(rtos
->target
,
520 ptr
+ param
->offsets
[OFFSET_T_NEXT_THREAD
],
522 if (retval
!= ERROR_OK
)
525 retval
= target_read_u32(rtos
->target
,
526 ptr
+ param
->offsets
[OFFSET_T_STACK_POINTER
],
527 &thread
->stack_pointer
);
528 if (retval
!= ERROR_OK
)
531 retval
= target_read_u8(rtos
->target
, ptr
+ param
->offsets
[OFFSET_T_STATE
],
533 if (retval
!= ERROR_OK
)
536 retval
= target_read_u8(rtos
->target
,
537 ptr
+ param
->offsets
[OFFSET_T_USER_OPTIONS
],
538 &thread
->user_options
);
539 if (retval
!= ERROR_OK
)
543 retval
= target_read_u8(rtos
->target
,
544 ptr
+ param
->offsets
[OFFSET_T_PRIO
], &prio
);
545 if (retval
!= ERROR_OK
)
549 thread
->name
[0] = '\0';
550 if (param
->offsets
[OFFSET_T_NAME
] != UNIMPLEMENTED
) {
551 retval
= target_read_buffer(rtos
->target
,
552 ptr
+ param
->offsets
[OFFSET_T_NAME
],
553 sizeof(thread
->name
) - 1, (uint8_t *)thread
->name
);
554 if (retval
!= ERROR_OK
)
557 thread
->name
[sizeof(thread
->name
) - 1] = '\0';
560 LOG_DEBUG("Fetched thread%" PRIx32
": {entry@0x%" PRIx32
561 ", state=%" PRIu8
", useropts=%" PRIu8
", prio=%" PRId8
"}",
562 ptr
, thread
->entry
, thread
->state
, thread
->user_options
, thread
->prio
);
567 static int zephyr_fetch_thread_list(struct rtos
*rtos
, uint32_t current_thread
)
569 struct zephyr_array thread_array
;
570 struct zephyr_thread thread
;
571 struct thread_detail
*td
;
572 int64_t curr_id
= -1;
576 retval
= target_read_u32(rtos
->target
, zephyr_kptr(rtos
, OFFSET_K_THREADS
),
578 if (retval
!= ERROR_OK
) {
579 LOG_ERROR("Could not fetch current thread pointer");
583 zephyr_array_init(&thread_array
);
585 for (; curr
; curr
= thread
.next_ptr
) {
586 retval
= zephyr_fetch_thread(rtos
, &thread
, curr
);
587 if (retval
!= ERROR_OK
)
590 td
= zephyr_array_append(&thread_array
, sizeof(*td
));
594 td
->threadid
= thread
.ptr
;
598 td
->thread_name_str
= strdup(thread
.name
);
600 td
->thread_name_str
= alloc_printf("thr_%" PRIx32
"_%" PRIx32
,
601 thread
.entry
, thread
.ptr
);
602 td
->extra_info_str
= alloc_printf("prio:%" PRId8
",useropts:%" PRIu8
,
603 thread
.prio
, thread
.user_options
);
604 if (!td
->thread_name_str
|| !td
->extra_info_str
)
607 if (td
->threadid
== current_thread
)
608 curr_id
= (int64_t)thread_array
.elements
- 1;
611 LOG_DEBUG("Got information for %zu threads", thread_array
.elements
);
613 rtos_free_threadlist(rtos
);
615 rtos
->thread_count
= (int)thread_array
.elements
;
616 rtos
->thread_details
= zephyr_array_detach_ptr(&thread_array
);
618 rtos
->current_threadid
= curr_id
;
619 rtos
->current_thread
= current_thread
;
624 td
= thread_array
.ptr
;
625 for (size_t i
= 0; i
< thread_array
.elements
; i
++) {
626 free(td
[i
].thread_name_str
);
627 free(td
[i
].extra_info_str
);
630 zephyr_array_free(&thread_array
);
635 static int zephyr_update_threads(struct rtos
*rtos
)
637 struct zephyr_params
*param
;
640 if (!rtos
->rtos_specific_params
)
643 param
= (struct zephyr_params
*)rtos
->rtos_specific_params
;
645 if (!rtos
->symbols
) {
646 LOG_ERROR("No symbols for Zephyr");
650 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL
].address
== 0) {
651 LOG_ERROR("Can't obtain kernel struct from Zephyr");
655 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
== 0) {
656 LOG_ERROR("Please build Zephyr with CONFIG_OPENOCD option set");
660 retval
= target_read_u8(rtos
->target
,
661 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_SIZE_T_SIZE
].address
,
663 if (retval
!= ERROR_OK
) {
664 LOG_ERROR("Couldn't determine size of size_t from host");
668 if (param
->size_width
!= 4) {
669 LOG_ERROR("Only size_t of 4 bytes are supported");
673 if (rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
].address
) {
674 retval
= target_read_u32(rtos
->target
,
675 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_NUM_OFFSETS
].address
,
676 ¶m
->num_offsets
);
677 if (retval
!= ERROR_OK
) {
678 LOG_ERROR("Couldn't not fetch number of offsets from Zephyr");
682 if (param
->num_offsets
<= OFFSET_T_STACK_POINTER
) {
683 LOG_ERROR("Number of offsets too small");
687 retval
= target_read_u32(rtos
->target
,
688 rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
,
689 ¶m
->offsets
[OFFSET_VERSION
]);
690 if (retval
!= ERROR_OK
) {
691 LOG_ERROR("Couldn't not fetch offsets from Zephyr");
695 if (param
->offsets
[OFFSET_VERSION
] > 1) {
696 LOG_ERROR("Unexpected OpenOCD support version %" PRIu32
,
697 param
->offsets
[OFFSET_VERSION
]);
700 switch (param
->offsets
[OFFSET_VERSION
]) {
702 param
->num_offsets
= OFFSET_T_STACK_POINTER
+ 1;
705 param
->num_offsets
= OFFSET_T_COOP_FLOAT
+ 1;
709 /* We can fetch the whole array for version 0, as they're supposed
712 address
= rtos
->symbols
[ZEPHYR_VAL__KERNEL_OPENOCD_OFFSETS
].address
;
713 for (size_t i
= 0; i
< OFFSET_MAX
; i
++, address
+= param
->size_width
) {
714 if (i
>= param
->num_offsets
) {
715 param
->offsets
[i
] = UNIMPLEMENTED
;
719 retval
= target_read_u32(rtos
->target
, address
, ¶m
->offsets
[i
]);
720 if (retval
!= ERROR_OK
) {
721 LOG_ERROR("Could not fetch offsets from Zephyr");
726 LOG_DEBUG("Zephyr OpenOCD support version %" PRId32
,
727 param
->offsets
[OFFSET_VERSION
]);
729 uint32_t current_thread
;
730 retval
= target_read_u32(rtos
->target
,
731 zephyr_kptr(rtos
, OFFSET_K_CURR_THREAD
), ¤t_thread
);
732 if (retval
!= ERROR_OK
) {
733 LOG_ERROR("Could not obtain current thread ID");
737 retval
= zephyr_fetch_thread_list(rtos
, current_thread
);
738 if (retval
!= ERROR_OK
) {
739 LOG_ERROR("Could not obtain thread list");
746 static int zephyr_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
747 struct rtos_reg
**reg_list
, int *num_regs
)
749 struct zephyr_params
*params
;
750 struct rtos_reg
*callee_saved_reg_list
= NULL
;
754 LOG_INFO("Getting thread %" PRId64
" reg list", thread_id
);
762 params
= rtos
->rtos_specific_params
;
766 addr
= thread_id
+ params
->offsets
[OFFSET_T_STACK_POINTER
]
767 - params
->callee_saved_stacking
->register_offsets
[0].offset
;
769 retval
= params
->get_cpu_state(rtos
, &addr
, params
, callee_saved_reg_list
, reg_list
, num_regs
);
771 free(callee_saved_reg_list
);
776 static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem
**symbol_list
)
778 *symbol_list
= malloc(sizeof(zephyr_symbol_list
));
780 LOG_ERROR("Out of memory");
784 memcpy(*symbol_list
, zephyr_symbol_list
, sizeof(zephyr_symbol_list
));
788 const struct rtos_type zephyr_rtos
= {
791 .detect_rtos
= zephyr_detect_rtos
,
792 .create
= zephyr_create
,
793 .update_threads
= zephyr_update_threads
,
794 .get_thread_reg_list
= zephyr_get_thread_reg_list
,
795 .get_symbol_list_to_lookup
= zephyr_get_symbol_list_to_lookup
,