Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright (c) 2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2025-08-16 Rbb666 first version
  9. */
  10. #include "coredump.h"
  11. #include "registers.h"
  12. #define FPU_CPACR 0xE000ED88
  13. int is_vfp_addressable(void)
  14. {
  15. uint32_t reg_cpacr = *((volatile uint32_t *)FPU_CPACR);
  16. if (reg_cpacr & 0x00F00000)
  17. return 1;
  18. else
  19. return 0;
  20. }
  21. #if defined(__CC_ARM)
  22. /* clang-format off */
  23. __asm void mcd_mini_dump()
  24. {
  25. extern get_cur_core_regset_address;
  26. extern get_cur_fp_regset_address;
  27. extern mcd_mini_dump_ops;
  28. extern mcd_gen_coredump;
  29. extern is_vfp_addressable;
  30. PRESERVE8
  31. push {r7, lr}
  32. sub sp, sp, #24
  33. add r7, sp, #0
  34. get_regset
  35. bl get_cur_core_regset_address
  36. str r0, [r0, #0]
  37. add r0, r0, #4
  38. stmia r0!, {r1 - r12}
  39. mov r1, sp
  40. add r1, #32
  41. str r1, [r0, #0]
  42. ldr r1, [sp, #28]
  43. str r1, [r0, #4]
  44. mov r1, pc
  45. str r1, [r0, #8]
  46. mrs r1, xpsr
  47. str r1, [r0, #12]
  48. bl is_vfp_addressable
  49. cmp r0, #0
  50. beq get_reg_done
  51. bl get_cur_fp_regset_address
  52. vstmia r0!, {d0 - d15}
  53. vmrs r1, fpscr
  54. str r1, [r0, #0]
  55. get_reg_done
  56. mov r0, r7
  57. bl mcd_mini_dump_ops
  58. mov r0, r7
  59. bl mcd_gen_coredump
  60. nop
  61. adds r7, r7, #24
  62. mov sp, r7
  63. pop {r7, pc}
  64. nop
  65. nop
  66. }
  67. __asm void mcd_multi_dump(void)
  68. {
  69. extern get_cur_core_regset_address;
  70. extern get_cur_fp_regset_address;
  71. extern mcd_rtos_thread_ops;
  72. extern mcd_gen_coredump;
  73. extern is_vfp_addressable;
  74. PRESERVE8
  75. push {r7, lr}
  76. sub sp, sp, #24
  77. add r7, sp, #0
  78. get_regset1
  79. bl get_cur_core_regset_address
  80. str r0, [r0, #0]
  81. add r0, r0, #4
  82. stmia r0!, {r1 - r12}
  83. mov r1, sp
  84. add r1, #32
  85. str r1, [r0, #0]
  86. ldr r1, [sp, #28]
  87. str r1, [r0, #4]
  88. mov r1, pc
  89. str r1, [r0, #8]
  90. mrs r1, xpsr
  91. str r1, [r0, #12]
  92. bl is_vfp_addressable
  93. cmp r0, #0
  94. beq get_reg_done
  95. bl get_cur_fp_regset_address
  96. vstmia r0!, {d0 - d15}
  97. vmrs r1, fpscr
  98. str r1, [r0, #0]
  99. get_reg_done1
  100. mov r0, r7
  101. bl mcd_rtos_thread_ops
  102. mov r0, r7
  103. bl mcd_gen_coredump
  104. nop
  105. adds r7, r7, #24
  106. mov sp, r7
  107. pop {r7, pc}
  108. nop
  109. nop
  110. }
  111. #elif 1 //defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) || defined(__GNUC__)
  112. #define mcd_get_regset(regset) \
  113. __asm volatile(" mov r0, %0 \n" \
  114. " str r0, [r0 , #0] \n" \
  115. " add r0, r0, #4 \n" \
  116. " stmia r0!, {r1 - r12} \n" \
  117. " mov r1, sp \n" \
  118. " str r1, [r0, #0] \n" \
  119. " mov r1, lr \n" \
  120. " str r1, [r0, #4] \n" \
  121. " mov r1, pc \n" \
  122. " str r1, [r0, #8] \n" \
  123. " mrs r1, xpsr \n" \
  124. " str r1, [r0, #12] \n" ::"r"(regset) \
  125. : "memory", "cc");
  126. #define mcd_get_fpregset(regset) \
  127. __asm volatile(" mov r0, %0 \n" \
  128. " vstmia r0!, {d0 - d15} \n" \
  129. " vmrs r1, fpscr \n" \
  130. " str r1, [r0, #0] \n" ::"r"(regset) \
  131. : "memory", "cc");
  132. // 不更新当前寄存器到全局变量(在异常中断中已填充)
  133. void mcd_hard_fault_exception_dump(void)
  134. {
  135. struct thread_info_ops ops;
  136. mcd_rtos_thread_ops(&ops);
  137. mcd_gen_coredump(&ops);
  138. if (ops.print_info_string)
  139. ops.print_info_string(&ops);
  140. }
  141. // 只保存当前线程或非线程(主栈):更新当前寄存器到全局变量
  142. void mcd_mini_dump(void)
  143. {
  144. struct thread_info_ops ops;
  145. mcd_get_regset((uint32_t *)get_cur_core_regset_address());
  146. #if MCD_FPU_SUPPORT
  147. if (is_vfp_addressable())
  148. mcd_get_fpregset((uint32_t *)get_cur_fp_regset_address());
  149. #endif
  150. mcd_mini_dump_ops(&ops);
  151. mcd_gen_coredump(&ops);
  152. if (ops.print_info_string)
  153. ops.print_info_string(&ops);
  154. }
  155. // 保存RTOS所有线程:更新当前寄存器到全局变量
  156. void mcd_multi_dump(void)
  157. {
  158. struct thread_info_ops ops;
  159. mcd_get_regset((uint32_t *)get_cur_core_regset_address());
  160. #if MCD_FPU_SUPPORT
  161. if (is_vfp_addressable())
  162. mcd_get_fpregset((uint32_t *)get_cur_fp_regset_address());
  163. #endif
  164. mcd_rtos_thread_ops(&ops);
  165. mcd_gen_coredump(&ops);
  166. if (ops.print_info_string)
  167. ops.print_info_string(&ops);
  168. }
  169. #endif
  170. // 有架构区别
  171. void print_registers_armv7m(core_regset_type *reg, fp_regset_type *fp_reg, char *thread)
  172. {
  173. mcd_print("Registers@%s\n", thread);
  174. mcd_print("R13(SP): 0x%08x\n", reg->sp);
  175. #if 0
  176. mcd_print("R0: 0x%08x\n", reg->r0);
  177. mcd_print("R1: 0x%08x\n", reg->r1);
  178. mcd_print("R2: 0x%08x\n", reg->r2);
  179. mcd_print("R3: 0x%08x\n", reg->r3);
  180. mcd_print("R4: 0x%08x\n", reg->r4);
  181. mcd_print("R5: 0x%08x\n", reg->r5);
  182. mcd_print("R6: 0x%08x\n", reg->r6);
  183. mcd_print("R7: 0x%08x\n", reg->r7);
  184. mcd_print("R8: 0x%08x\n", reg->r8);
  185. mcd_print("R9: 0x%08x\n", reg->r9);
  186. mcd_print("R10: 0x%08x\n", reg->r10);
  187. mcd_print("R11: 0x%08x\n", reg->r11);
  188. mcd_print("R12: 0x%08x\n", reg->r12);
  189. mcd_print("R13(SP): 0x%08x\n", reg->sp);
  190. mcd_print("R14(LR): 0x%08x\n", reg->lr);
  191. mcd_print("R15(PC): 0x%08x\n", reg->pc);
  192. mcd_print("xPSR: 0x%08x\n", reg->xpsr);
  193. #else // 按压栈顺序打印
  194. mcd_print("xPSR: 0x%08x\n", reg->xpsr);
  195. mcd_print("R15(PC): 0x%08x\n", reg->pc);
  196. mcd_print("R14(LR): 0x%08x\n", reg->lr);
  197. mcd_print("R12: 0x%08x\n", reg->r12);
  198. mcd_print("R3: 0x%08x\n", reg->r3);
  199. mcd_print("R2: 0x%08x\n", reg->r2);
  200. mcd_print("R1: 0x%08x\n", reg->r1);
  201. mcd_print("R0: 0x%08x\n", reg->r0);
  202. mcd_print("R11: 0x%08x\n", reg->r11);
  203. mcd_print("R10: 0x%08x\n", reg->r10);
  204. mcd_print("R9: 0x%08x\n", reg->r9);
  205. mcd_print("R8: 0x%08x\n", reg->r8);
  206. mcd_print("R7: 0x%08x\n", reg->r7);
  207. mcd_print("R6: 0x%08x\n", reg->r6);
  208. mcd_print("R5: 0x%08x\n", reg->r5);
  209. mcd_print("R4: 0x%08x\n", reg->r4);
  210. #endif
  211. }
  212. /**
  213. * @brief Collect ARM Cortex-M4 registers from RT-Thread stack frame
  214. *
  215. * This function extracts register values from the stack frame created by
  216. * RT-Thread's context switch mechanism (PendSV_Handler) or exception handling.
  217. *
  218. * RT-Thread Stack Frame Layout (from low to high memory address):
  219. * +-------------------+ <- stack_top (input parameter)
  220. * | FPU flag | (4 bytes, if MCD_FPU_SUPPORT enabled)
  221. * +-------------------+
  222. * | r4 | (4 bytes, software saved)
  223. * | r5 | (4 bytes, software saved)
  224. * | r6 | (4 bytes, software saved)
  225. * | r7 | (4 bytes, software saved)
  226. * | r8 | (4 bytes, software saved)
  227. * | r9 | (4 bytes, software saved)
  228. * | r10 | (4 bytes, software saved)
  229. * | r11 | (4 bytes, software saved)
  230. * +-------------------+
  231. * | FPU s16-s31 | (64 bytes, if FPU context active)
  232. * +-------------------+
  233. * | r0 | (4 bytes, hardware saved)
  234. * | r1 | (4 bytes, hardware saved)
  235. * | r2 | (4 bytes, hardware saved)
  236. * | r3 | (4 bytes, hardware saved)
  237. * | r12 | (4 bytes, hardware saved)
  238. * | lr | (4 bytes, hardware saved)
  239. * | pc | (4 bytes, hardware saved)
  240. * | xpsr | (4 bytes, hardware saved)
  241. * +-------------------+
  242. * | FPU s0-s15 | (64 bytes, if FPU context active)
  243. * | FPSCR | (4 bytes, if FPU context active)
  244. * | NO_NAME | (4 bytes, if FPU context active)
  245. * +-------------------+ <- current SP after context save
  246. *
  247. * @param stack_top Pointer to the beginning of the stack frame (FPU flag position)
  248. * @param core_regset Pointer to structure for storing ARM core registers
  249. * @param fp_regset Pointer to structure for storing FPU registers
  250. */
  251. // 通过sp指针得到寄存器信息
  252. void collect_registers_armv7m(uint32_t *stack_top, core_regset_type *core_regset, fp_regset_type *fp_regset)
  253. {
  254. /*
  255. * This function uses the same stack frame parsing approach as collect_registers_armv7ms
  256. * for consistency. Both PendSV_Handler and HardFault_Handler now use identical
  257. * stacking order after the modifications.
  258. *
  259. * Expected stack layout starting from stack_top:
  260. * [FPU flag] -> [r4-r11] -> [FPU s16-s31] -> [exception frame] -> [FPU s0-s15,FPSCR]
  261. */
  262. uint32_t *current_ptr = stack_top;
  263. /* Clear both register sets first to ensure clean state */
  264. mcd_memset(core_regset, 0, sizeof(core_regset_type));
  265. mcd_memset(fp_regset, 0, sizeof(fp_regset_type));
  266. #if MCD_FPU_SUPPORT
  267. /* Read FPU flag first - indicates if FPU context was saved */
  268. uint32_t fpu_flag = *current_ptr++;
  269. #endif
  270. /* Extract core registers r4-r11 (software saved by RT-Thread) */
  271. core_regset->r4 = *current_ptr++;
  272. core_regset->r5 = *current_ptr++;
  273. core_regset->r6 = *current_ptr++;
  274. core_regset->r7 = *current_ptr++;
  275. core_regset->r8 = *current_ptr++;
  276. core_regset->r9 = *current_ptr++;
  277. core_regset->r10 = *current_ptr++;
  278. core_regset->r11 = *current_ptr++;
  279. #if MCD_FPU_SUPPORT
  280. /* If FPU context is active, s16-s31 registers are saved after r4-r11 */
  281. if (fpu_flag)
  282. {
  283. /* Copy FPU s16-s31 registers (software saved by RT-Thread) */
  284. for (int i = 16; i < 32; i++)
  285. {
  286. ((uint32_t *)fp_regset)[i] = *current_ptr++;
  287. }
  288. }
  289. #endif
  290. /* Extract hardware exception frame (automatically saved by ARM Cortex-M) */
  291. core_regset->r0 = *current_ptr++;
  292. core_regset->r1 = *current_ptr++;
  293. core_regset->r2 = *current_ptr++;
  294. core_regset->r3 = *current_ptr++;
  295. core_regset->r12 = *current_ptr++;
  296. core_regset->lr = *current_ptr++;
  297. core_regset->pc = *current_ptr++;
  298. core_regset->xpsr = *current_ptr++;
  299. #if MCD_FPU_SUPPORT
  300. /* If FPU context is active, s0-s15 and FPSCR are saved after exception frame */
  301. if (fpu_flag)
  302. {
  303. /* Copy FPU s0-s15 registers (hardware saved by ARM Cortex-M) */
  304. for (int i = 0; i < 16; i++)
  305. {
  306. ((uint32_t *)fp_regset)[i] = *current_ptr++;
  307. }
  308. /* Copy FPSCR register (FPU status and control) */
  309. fp_regset->fpscr = *current_ptr++;
  310. /* Skip NO_NAME field (reserved/alignment) */
  311. current_ptr++;
  312. }
  313. #endif
  314. /* SP should point to the current stack pointer position after all saved data */
  315. core_regset->sp = (uintptr_t)current_ptr;
  316. }
  317. /**
  318. * @brief ARM Cortex-M specific hard fault exception handler for MCoreDump
  319. *
  320. * This function handles ARM Cortex-M specific stack frame processing when a
  321. * hard fault occurs. It calculates the proper stack pointer position and
  322. * extracts register context for coredump generation.
  323. *
  324. * HardFault Stack Frame Layout (created by HardFault_Handler):
  325. * +-------------------+ <- Exception occurs here
  326. * | Hardware Exception| (32 bytes: r0,r1,r2,r3,r12,lr,pc,xpsr)
  327. * | Stack Frame | (+ optional 72 bytes FPU: s0-s15,FPSCR,NO_NAME)
  328. * +-------------------+ <- context parameter points here
  329. * | r11 | (4 bytes, software saved in HardFault_Handler)
  330. * | r10 | (4 bytes, software saved in HardFault_Handler)
  331. * | ... | (...)
  332. * | r4 | (4 bytes, software saved in HardFault_Handler)
  333. * +-------------------+
  334. * | FPU s31 | (4 bytes, if FPU context active)
  335. * | FPU s30 | (4 bytes, if FPU context active)
  336. * | ... | (...)
  337. * | FPU s16 | (4 bytes, if FPU context active)
  338. * +-------------------+
  339. * | FPU flag | (4 bytes, if MCD_FPU_SUPPORT enabled)
  340. * +-------------------+
  341. * | EXC_RETURN | (4 bytes, contains exception return information)
  342. * +-------------------+ <- Final stack pointer position
  343. *
  344. * @param context Pointer to exception_stack_frame from HardFault_Handler
  345. * @return int Always returns -1 to indicate fault condition
  346. */
  347. int armv7m_hard_fault_exception_hook(void *context)
  348. {
  349. /*
  350. * context points to exception_stack_frame created by HardFault_Handler.
  351. * We need to calculate the complete stack frame position to extract all registers.
  352. * Since HardFault_Handler now uses the same stacking order as PendSV_Handler,
  353. * we can directly use collect_registers_armv7m function.
  354. */
  355. #if 0
  356. struct exception_stack_frame *exception_stack = (struct exception_stack_frame *)context;
  357. /* Calculate stack pointer to the beginning of the saved context */
  358. uint32_t *stack_ptr = (uint32_t *)exception_stack;
  359. /*
  360. * Move backward through the stack to reach the beginning of saved context.
  361. * Stack layout (working backwards from exception_stack):
  362. * exception_stack -> r4-r11 (8 words) -> [s16-s31] -> [fpu_flag] -> [exc_return]
  363. */
  364. stack_ptr -= 8; /* Move backward 8 uint32_t positions to reach r4 */
  365. #if MCD_FPU_SUPPORT
  366. /* Point to FPU flag position (collect_registers_armv7m expects this as start) */
  367. stack_ptr -= 1; /* fpu flag */
  368. #else
  369. /* If no FPU support, skip EXC_RETURN and point to r4 directly */
  370. stack_ptr -= 1; /* exc_return */
  371. #endif
  372. #else
  373. uint32_t *stack_ptr = context;
  374. stack_ptr += 1; /* 跳过:exc_return */
  375. // stack_ptr += 1; // 如开启fpuflag
  376. #endif
  377. /*
  378. * Now stack_ptr points to where collect_registers_armv7m expects:
  379. * - With FPU: points to FPU flag (first field to be read)
  380. * - Without FPU: points to r4 (first register to be read)
  381. */
  382. collect_registers_armv7m(stack_ptr, get_cur_core_regset_address(), get_cur_fp_regset_address());
  383. /* Generate coredump using memory mode */
  384. mcd_faultdump(MCD_OUTPUT_FAULT_SERIAL);
  385. return 0;
  386. }