| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- /*
- * Copyright (c) 2025, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2025-08-16 Rbb666 first version
- */
-
- #include "coredump.h"
- #include "registers.h"
-
- #define FPU_CPACR 0xE000ED88
-
- int is_vfp_addressable(void)
- {
- uint32_t reg_cpacr = *((volatile uint32_t *)FPU_CPACR);
- if (reg_cpacr & 0x00F00000)
- return 1;
- else
- return 0;
- }
-
- #if defined(__CC_ARM)
-
- /* clang-format off */
- __asm void mcd_mini_dump()
- {
- extern get_cur_core_regset_address;
- extern get_cur_fp_regset_address;
- extern mcd_mini_dump_ops;
- extern mcd_gen_coredump;
- extern is_vfp_addressable;
-
- PRESERVE8
-
- push {r7, lr}
- sub sp, sp, #24
- add r7, sp, #0
-
- get_regset
- bl get_cur_core_regset_address
- str r0, [r0, #0]
- add r0, r0, #4
- stmia r0!, {r1 - r12}
- mov r1, sp
- add r1, #32
- str r1, [r0, #0]
- ldr r1, [sp, #28]
- str r1, [r0, #4]
- mov r1, pc
- str r1, [r0, #8]
- mrs r1, xpsr
- str r1, [r0, #12]
-
- bl is_vfp_addressable
- cmp r0, #0
- beq get_reg_done
-
- bl get_cur_fp_regset_address
- vstmia r0!, {d0 - d15}
- vmrs r1, fpscr
- str r1, [r0, #0]
-
- get_reg_done
- mov r0, r7
- bl mcd_mini_dump_ops
- mov r0, r7
- bl mcd_gen_coredump
- nop
- adds r7, r7, #24
- mov sp, r7
- pop {r7, pc}
- nop
- nop
- }
-
- __asm void mcd_multi_dump(void)
- {
- extern get_cur_core_regset_address;
- extern get_cur_fp_regset_address;
- extern mcd_rtos_thread_ops;
- extern mcd_gen_coredump;
- extern is_vfp_addressable;
-
- PRESERVE8
-
- push {r7, lr}
- sub sp, sp, #24
- add r7, sp, #0
-
- get_regset1
- bl get_cur_core_regset_address
- str r0, [r0, #0]
- add r0, r0, #4
- stmia r0!, {r1 - r12}
- mov r1, sp
- add r1, #32
- str r1, [r0, #0]
- ldr r1, [sp, #28]
- str r1, [r0, #4]
- mov r1, pc
- str r1, [r0, #8]
- mrs r1, xpsr
- str r1, [r0, #12]
-
- bl is_vfp_addressable
- cmp r0, #0
- beq get_reg_done
-
- bl get_cur_fp_regset_address
- vstmia r0!, {d0 - d15}
- vmrs r1, fpscr
- str r1, [r0, #0]
-
- get_reg_done1
- mov r0, r7
- bl mcd_rtos_thread_ops
- mov r0, r7
- bl mcd_gen_coredump
- nop
- adds r7, r7, #24
- mov sp, r7
- pop {r7, pc}
- nop
- nop
- }
-
- #elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) || defined(__GNUC__)
-
- #define mcd_get_regset(regset) \
- __asm volatile(" mov r0, %0 \n" \
- " str r0, [r0 , #0] \n" \
- " add r0, r0, #4 \n" \
- " stmia r0!, {r1 - r12} \n" \
- " mov r1, sp \n" \
- " str r1, [r0, #0] \n" \
- " mov r1, lr \n" \
- " str r1, [r0, #4] \n" \
- " mov r1, pc \n" \
- " str r1, [r0, #8] \n" \
- " mrs r1, xpsr \n" \
- " str r1, [r0, #12] \n" ::"r"(regset) \
- : "memory", "cc");
-
- #define mcd_get_fpregset(regset) \
- __asm volatile(" mov r0, %0 \n" \
- " vstmia r0!, {d0 - d15} \n" \
- " vmrs r1, fpscr \n" \
- " str r1, [r0, #0] \n" ::"r"(regset) \
- : "memory", "cc");
-
- void mcd_mini_dump(void)
- {
- struct thread_info_ops ops;
-
- mcd_get_regset((uint32_t *)get_cur_core_regset_address());
-
- #if MCD_FPU_SUPPORT
- if (is_vfp_addressable())
- mcd_get_fpregset((uint32_t *)get_cur_fp_regset_address());
- #endif
-
- mcd_mini_dump_ops(&ops);
- mcd_gen_coredump(&ops);
- }
-
- void mcd_multi_dump(void)
- {
- struct thread_info_ops ops;
-
- mcd_get_regset((uint32_t *)get_cur_core_regset_address());
-
- #if MCD_FPU_SUPPORT
- if (is_vfp_addressable())
- mcd_get_fpregset((uint32_t *)get_cur_fp_regset_address());
- #endif
-
- mcd_rtos_thread_ops(&ops);
- mcd_gen_coredump(&ops);
- }
-
- #endif
-
- /**
- * @brief Collect ARM Cortex-M33 registers from RT-Thread stack frame
- *
- * This function extracts register values from the stack frame created by
- * RT-Thread's HardFault_Handler for ARMv8-M architecture.
- *
- * ARMv8-M Stack Frame Layout (based on HardFault_Handler in context_gcc.S):
- * +-------------------+ <- stack_top (input parameter)
- * | EXC_RETURN | (4 bytes, contains exception return information)
- * +-------------------+
- * | tz | (4 bytes, TrustZone context)
- * | lr | (4 bytes, saved link register)
- * | psplim | (4 bytes, stack pointer limit)
- * | control | (4 bytes, control register)
- * +-------------------+
- * | r4 | (4 bytes, software saved)
- * | r5 | (4 bytes, software saved)
- * | r6 | (4 bytes, software saved)
- * | r7 | (4 bytes, software saved)
- * | r8 | (4 bytes, software saved)
- * | r9 | (4 bytes, software saved)
- * | r10 | (4 bytes, software saved)
- * | r11 | (4 bytes, software saved)
- * +-------------------+
- * | FPU d8-d15 | (64 bytes, if FPU context active)
- * +-------------------+
- * | r0 | (4 bytes, hardware saved)
- * | r1 | (4 bytes, hardware saved)
- * | r2 | (4 bytes, hardware saved)
- * | r3 | (4 bytes, hardware saved)
- * | r12 | (4 bytes, hardware saved)
- * | lr | (4 bytes, hardware saved)
- * | pc | (4 bytes, hardware saved)
- * | xpsr | (4 bytes, hardware saved)
- * +-------------------+
- * | FPU d0-d7 | (64 bytes, if FPU context active)
- * | FPSCR | (4 bytes, if FPU context active)
- * | NO_NAME | (4 bytes, if FPU context active)
- * +-------------------+ <- current SP after context save
- *
- * @param stack_top Pointer to the beginning of the stack frame (EXC_RETURN position)
- * @param core_regset Pointer to structure for storing ARM core registers
- * @param fp_regset Pointer to structure for storing FPU registers
- */
- void collect_registers_armv8m(uint32_t *stack_top,
- core_regset_type *core_regset,
- fp_regset_type *fp_regset)
- {
- /*
- * ARMv8-M has two different stack layouts:
- * 1. Exception context (HardFault_Handler): [EXC_RETURN] -> [tz,lr,psplim,control] -> [r4-r11] -> [FPU d8-d15] -> [exception frame] -> [FPU d0-d7,FPSCR]
- * 2. Normal thread context (PendSV_Handler): [tz,lr,psplim,control] -> [r4-r11] -> [hardware exception frame]
- */
- uint32_t *current_ptr = stack_top;
-
- /* Clear both register sets first to ensure clean state */
- mcd_memset(core_regset, 0, sizeof(core_regset_type));
- mcd_memset(fp_regset, 0, sizeof(fp_regset_type));
-
- /* Read first word to determine context type */
- uint32_t first_word = *current_ptr;
- uint32_t fpu_flag = 0; // Default to no FPU context
-
- /* Check if this is a valid EXC_RETURN value (starts with 0xFF) */
- if ((first_word & 0xFF000000) == 0xFF000000)
- {
- /* Valid EXC_RETURN - this is an exception context */
- uint32_t exc_return = *current_ptr++;
- fpu_flag = !(exc_return & 0x10);
- /* Skip tz, lr, psplim, control fields (4 words) */
- current_ptr += 4;
- }
- else
- {
- /* Not a valid EXC_RETURN - this is normal thread context from PendSV_Handler */
- fpu_flag = 0;
- /* For normal thread context, stack_top points to [tz,lr,psplim,control] */
- /* Skip tz, lr, psplim, control fields (4 words) */
- current_ptr += 4;
- }
-
- /* Extract core registers r4-r11 (software saved by RT-Thread) */
- core_regset->r4 = *current_ptr++;
- core_regset->r5 = *current_ptr++;
- core_regset->r6 = *current_ptr++;
- core_regset->r7 = *current_ptr++;
- core_regset->r8 = *current_ptr++;
- core_regset->r9 = *current_ptr++;
- core_regset->r10 = *current_ptr++;
- core_regset->r11 = *current_ptr++;
-
- #if MCD_FPU_SUPPORT
- /* If FPU context is active, d8-d15 registers are saved after r4-r11 */
- if (fpu_flag)
- {
- /* Copy FPU d8-d15 registers (software saved by HardFault_Handler) */
- /* Each double precision register is 64 bits = 2 words */
- uint64_t *fp_d_ptr = (uint64_t *)current_ptr;
- for (int i = 0; i < 8; i++) /* d8-d15 = 8 registers */
- {
- (&fp_regset->d8)[i] = *fp_d_ptr++;
- }
- current_ptr = (uint32_t *)fp_d_ptr;
- }
- #endif
-
- /* Extract hardware exception frame (automatically saved by ARM Cortex-M) */
- core_regset->r0 = *current_ptr++;
- core_regset->r1 = *current_ptr++;
- core_regset->r2 = *current_ptr++;
- core_regset->r3 = *current_ptr++;
- core_regset->r12 = *current_ptr++;
- core_regset->lr = *current_ptr++;
- core_regset->pc = *current_ptr++;
- core_regset->xpsr = *current_ptr++;
-
- #if MCD_FPU_SUPPORT
- /* If FPU context is active, d0-d7 and FPSCR are saved after exception frame */
- if (fpu_flag)
- {
- /* Copy FPU d0-d7 registers (hardware saved by ARM Cortex-M) */
- /* Each double precision register is 64 bits = 2 words */
- uint64_t *fp_d_ptr = (uint64_t *)current_ptr;
- for (int i = 0; i < 8; i++) /* d0-d7 = 8 registers */
- {
- (&fp_regset->d0)[i] = *fp_d_ptr++;
- }
- current_ptr = (uint32_t *)fp_d_ptr;
-
- /* Copy FPSCR register (FPU status and control) */
- fp_regset->fpscr = *current_ptr++;
-
- /* Skip NO_NAME field (reserved/alignment) */
- current_ptr++;
- }
- #endif
-
- /* SP should point to the current stack pointer position after all saved data */
- core_regset->sp = (uintptr_t)current_ptr;
- }
-
- /**
- * @brief ARM Cortex-M33 specific hard fault exception handler for MCoreDump
- *
- * This function handles ARM Cortex-M33 specific stack frame processing when a
- * hard fault occurs. It follows the armv7m approach for simple and reliable
- * stack pointer calculation.
- *
- * HardFault Stack Frame Layout (created by HardFault_Handler):
- * +-------------------+ <- Exception occurs here
- * | Hardware Exception| (32 bytes: r0,r1,r2,r3,r12,lr,pc,xpsr)
- * | Stack Frame | (+ optional 72 bytes FPU: s0-s15,FPSCR,NO_NAME)
- * +-------------------+ <- context parameter points here
- * | r11 | (4 bytes, software saved in HardFault_Handler)
- * | r10 | (4 bytes, software saved in HardFault_Handler)
- * | ... | (...)
- * | r4 | (4 bytes, software saved in HardFault_Handler)
- * +-------------------+
- * | FPU s31 | (4 bytes, if FPU context active)
- * | FPU s30 | (4 bytes, if FPU context active)
- * | ... | (...)
- * | FPU s16 | (4 bytes, if FPU context active)
- * +-------------------+
- * | FPU flag | (4 bytes, if MCD_FPU_SUPPORT enabled)
- * +-------------------+ <- Target position for collect_registers_armv8m
- *
- * @param context Pointer to exception_stack_frame from HardFault_Handler
- * @return int Always returns 0 after processing coredump
- */
- int armv8m_hard_fault_exception_hook(void *context)
- {
- /* Add debug output to confirm we reach this function */
- mcd_print("armv8m_hard_fault_exception_hook called, context = 0x%08x\n", (uint32_t)context);
-
- /*
- * Based on HardFault_Handler implementation in context_gcc.S:
- *
- * For EXCEPTION context (HardFault_Handler):
- * Stack layout from context (exception_stack_frame) backwards:
- * context -> [r0,r1,r2,r3,r12,lr,pc,xpsr] (exception frame)
- * context-32 -> [r11,r10,r9,r8,r7,r6,r5,r4] (8 words, STMFD r0!, {r4-r11})
- * context-48 -> [tz,lr,psplim,control] (4 words, STMFD r0!, {r2-r5})
- * context-52 -> [EXC_RETURN] (1 word, STMFD r0!, {lr})
- *
- * We need to point to EXC_RETURN for collect_registers_armv8m
- */
-
- uint32_t *stack_ptr = (uint32_t *)context;
-
- /* Move backwards to find EXC_RETURN position */
- stack_ptr -= 8; /* r4-r11 (8 registers) */
- stack_ptr -= 4; /* tz, lr, psplim, control (4 fields) */
- stack_ptr -= 1; /* EXC_RETURN */
-
- #ifdef RT_USING_FINSH
- extern long list_thread(void);
- list_thread();
- #endif
-
- /* Now stack_ptr points to EXC_RETURN, which is what collect_registers_armv8m expects */
- collect_registers_armv8m(stack_ptr,
- get_cur_core_regset_address(),
- get_cur_fp_regset_address());
-
- /* Generate coredump using memory mode */
- mcd_faultdump(MCD_OUTPUT_MEMORY);
-
- return 0;
- }
|