crash_console_helpers.S 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (c) 2018-2024, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /*
  7. * If a platform wishes to use the functions in this file it has to be added to
  8. * the Makefile of the platform. It is not included in the common Makefile.
  9. */
  10. #include <asm_macros.S>
  11. #include <drivers/console.h>
  12. .globl plat_crash_console_init
  13. .globl plat_crash_console_putc
  14. .globl plat_crash_console_flush
  15. /*
  16. * Spinlock to syncronize access to crash_console_triggered. We cannot
  17. * acquire spinlocks when the cache is disabled, so in some cases (like
  18. * late during CPU suspend) some risk remains.
  19. */
  20. .section .data.crash_console_spinlock
  21. define_asm_spinlock crash_console_spinlock
  22. /*
  23. * Flag to make sure that only one CPU can write a crash dump even if
  24. * multiple crash at the same time. Interleaving crash dumps on the same
  25. * console would just make the output unreadable, so it's better to only
  26. * get a single but uncorrupted dump. This also means that we don't have
  27. * to duplicate the reg_stash below for each CPU.
  28. */
  29. .section .data.crash_console_triggered
  30. crash_console_triggered: .byte 0
  31. /*
  32. * Space to stash away some register values while we're calling into
  33. * console drivers and don't have a real stack available. We need x14,
  34. * x15 and x30 for bookkeeping within the plat_crash_console functions
  35. * themselves, and some console drivers use x16 and x17 as additional
  36. * scratch space that is not preserved by the main crash reporting
  37. * framework. (Note that x16 and x17 should really never be expected to
  38. * retain their values across any function call, even between carefully
  39. * designed assembly functions, since the linker is always free to
  40. * insert a function call veneer that uses these registers as scratch
  41. * space at any time. The current crash reporting framework doesn't
  42. * really respect that, but since TF is usually linked as a single
  43. * contiguous binary of less than 128MB, it seems to work in practice.)
  44. */
  45. .section .data.crash_console_reg_stash
  46. .align 3
  47. crash_console_reg_stash: .quad 0, 0, 0, 0, 0
  48. /* --------------------------------------------------------------------
  49. * int plat_crash_console_init(void)
  50. * Takes the crash console spinlock (if possible) and checks the trigger
  51. * flag to make sure we're the first CPU to dump. If not, return an
  52. * error (so crash dumping will fail but the CPU will still call
  53. * plat_panic_handler() which may do important platform-specific tasks
  54. * that may be needed on all crashing CPUs). In either case, the lock
  55. * will be released so other CPUs can make forward progress on this.
  56. * Clobbers: x0 - x4, x30
  57. * --------------------------------------------------------------------
  58. */
  59. func plat_crash_console_init
  60. #if defined(IMAGE_BL31)
  61. mov x4, x30 /* x3 and x4 are not clobbered by spin_lock() */
  62. mov x3, #0 /* return value */
  63. adrp x0, crash_console_spinlock
  64. add x0, x0, :lo12:crash_console_spinlock
  65. mrs x1, sctlr_el3
  66. tst x1, #SCTLR_C_BIT
  67. beq skip_spinlock /* can't synchronize when cache disabled */
  68. bl spin_lock
  69. skip_spinlock:
  70. adrp x1, crash_console_triggered
  71. add x1, x1, :lo12:crash_console_triggered
  72. ldarb w2, [x1]
  73. cmp w2, #0
  74. bne init_error
  75. mov x3, #1 /* set return value to success */
  76. stlrb w3, [x1]
  77. init_error:
  78. bl spin_unlock /* harmless if we didn't acquire the lock */
  79. mov x0, x3
  80. ret x4
  81. #else /* Only one CPU in BL1/BL2, no need to synchronize anything */
  82. mov x0, #1
  83. ret
  84. #endif
  85. endfunc plat_crash_console_init
  86. /* --------------------------------------------------------------------
  87. * int plat_crash_console_putc(char c)
  88. * Prints the character on all consoles registered with the console
  89. * framework that have CONSOLE_FLAG_CRASH set. Note that this is only
  90. * helpful for crashes that occur after the platform initialization code
  91. * has registered a console. Platforms using this implementation need to
  92. * ensure that all console drivers they use that have the CRASH flag set
  93. * support this (i.e. are written in assembly and comply to the register
  94. * clobber requirements of plat_crash_console_putc().
  95. * --------------------------------------------------------------------
  96. */
  97. func plat_crash_console_putc
  98. adrp x1, crash_console_reg_stash
  99. add x1, x1, :lo12:crash_console_reg_stash
  100. stp x14, x15, [x1]
  101. stp x16, x17, [x1, #16]
  102. str x30, [x1, #32]
  103. mov w14, w0 /* W14 = character to print */
  104. adrp x15, console_list
  105. ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */
  106. putc_loop:
  107. cbz x15, putc_done
  108. ldr w1, [x15, #CONSOLE_T_FLAGS]
  109. tst w1, #CONSOLE_FLAG_CRASH
  110. b.eq putc_continue
  111. ldr x2, [x15, #CONSOLE_T_PUTC]
  112. cbz x2, putc_continue
  113. cmp w14, #'\n'
  114. b.ne putc
  115. tst w1, #CONSOLE_FLAG_TRANSLATE_CRLF
  116. b.eq putc
  117. mov x1, x15
  118. mov w0, #'\r'
  119. blr x2
  120. ldr x2, [x15, #CONSOLE_T_PUTC]
  121. putc:
  122. mov x1, x15
  123. mov w0, w14
  124. blr x2
  125. putc_continue:
  126. ldr x15, [x15] /* X15 = next struct */
  127. b putc_loop
  128. putc_done:
  129. adrp x1, crash_console_reg_stash
  130. add x1, x1, :lo12:crash_console_reg_stash
  131. ldp x14, x15, [x1]
  132. ldp x16, x17, [x1, #16]
  133. ldr x30, [x1, #32]
  134. ret
  135. endfunc plat_crash_console_putc
  136. /* --------------------------------------------------------------------
  137. * int plat_crash_console_flush(char c)
  138. * Flushes all consoles registered with the console framework that have
  139. * CONSOLE_FLAG_CRASH set. Same requirements as putc().
  140. * --------------------------------------------------------------------
  141. */
  142. func plat_crash_console_flush
  143. adrp x1, crash_console_reg_stash
  144. add x1, x1, :lo12:crash_console_reg_stash
  145. stp x30, x15, [x1]
  146. stp x16, x17, [x1, #16]
  147. adrp x15, console_list
  148. ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */
  149. flush_loop:
  150. cbz x15, flush_done
  151. ldr w1, [x15, #CONSOLE_T_FLAGS]
  152. tst w1, #CONSOLE_FLAG_CRASH
  153. b.eq flush_continue
  154. ldr x2, [x15, #CONSOLE_T_FLUSH]
  155. cbz x2, flush_continue
  156. mov x0, x15
  157. blr x2
  158. flush_continue:
  159. ldr x15, [x15] /* X15 = next struct */
  160. b flush_loop
  161. flush_done:
  162. adrp x1, crash_console_reg_stash
  163. add x1, x1, :lo12:crash_console_reg_stash
  164. ldp x30, x15, [x1]
  165. ldp x16, x17, [x1, #16]
  166. ret
  167. endfunc plat_crash_console_flush