1/* 2 * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6#include <arch.h> 7#include <asm_macros.S> 8#include <context.h> 9#include <cpu_data.h> 10#include <plat_macros.S> 11#include <platform_def.h> 12 13 .globl report_unhandled_exception 14 .globl report_unhandled_interrupt 15 .globl el3_panic 16 17#if CRASH_REPORTING 18#define REG_SIZE 0x8 19 20 /* ------------------------------------------------------ 21 * The below section deals with dumping the system state 22 * when an unhandled exception is taken in EL3. 23 * The layout and the names of the registers which will 24 * be dumped during a unhandled exception is given below. 25 * ------------------------------------------------------ 26 */ 27.section .rodata.crash_prints, "aS" 28print_spacer: 29 .asciz " =\t\t0x" 30 31gp_regs: 32 .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\ 33 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\ 34 "x16", "x17", "x18", "x19", "x20", "x21", "x22",\ 35 "x23", "x24", "x25", "x26", "x27", "x28", "x29", "" 36el3_sys_regs: 37 .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\ 38 "daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\ 39 "esr_el3", "far_el3", "" 40 41non_el3_sys_regs: 42 .asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\ 43 "spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\ 44 "csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\ 45 "mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\ 46 "tpidrro_el0", "dacr32_el2", "ifsr32_el2", "par_el1",\ 47 "mpidr_el1", "afsr0_el1", "afsr1_el1", "contextidr_el1",\ 48 "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0", "cntv_ctl_el0",\ 49 "cntv_cval_el0", "cntkctl_el1", "fpexc32_el2", "sp_el0",\ 50 "isr_el1", "" 51 52panic_msg: 53 .asciz "PANIC in EL3 at x30 = 0x" 54excpt_msg: 55 .asciz "Unhandled Exception in EL3.\nx30 =\t\t0x" 56intr_excpt_msg: 57 .asciz "Unhandled Interrupt Exception in EL3.\nx30 =\t\t0x" 58 59 /* 60 * Helper function to print newline to console. 61 */ 62func print_newline 63 mov x0, '\n' 64 b plat_crash_console_putc 65endfunc print_newline 66 67 /* 68 * Helper function to print from crash buf. 69 * The print loop is controlled by the buf size and 70 * ascii reg name list which is passed in x6. The 71 * function returns the crash buf address in x0. 72 * Clobbers : x0 - x7, sp 73 */ 74func size_controlled_print 75 /* Save the lr */ 76 mov sp, x30 77 /* load the crash buf address */ 78 mrs x7, tpidr_el3 79test_size_list: 80 /* Calculate x5 always as it will be clobbered by asm_print_hex */ 81 mrs x5, tpidr_el3 82 add x5, x5, #CPU_DATA_CRASH_BUF_SIZE 83 /* Test whether we have reached end of crash buf */ 84 cmp x7, x5 85 b.eq exit_size_print 86 ldrb w4, [x6] 87 /* Test whether we are at end of list */ 88 cbz w4, exit_size_print 89 mov x4, x6 90 /* asm_print_str updates x4 to point to next entry in list */ 91 bl asm_print_str 92 /* update x6 with the updated list pointer */ 93 mov x6, x4 94 adr x4, print_spacer 95 bl asm_print_str 96 ldr x4, [x7], #REG_SIZE 97 bl asm_print_hex 98 bl print_newline 99 b test_size_list 100exit_size_print: 101 mov x30, sp 102 ret 103endfunc size_controlled_print 104 105 /* 106 * Helper function to store x8 - x15 registers to 107 * the crash buf. The system registers values are 108 * copied to x8 to x15 by the caller which are then 109 * copied to the crash buf by this function. 110 * x0 points to the crash buf. It then calls 111 * size_controlled_print to print to console. 112 * Clobbers : x0 - x7, sp 113 */ 114func str_in_crash_buf_print 115 /* restore the crash buf address in x0 */ 116 mrs x0, tpidr_el3 117 stp x8, x9, [x0] 118 stp x10, x11, [x0, #REG_SIZE * 2] 119 stp x12, x13, [x0, #REG_SIZE * 4] 120 stp x14, x15, [x0, #REG_SIZE * 6] 121 b size_controlled_print 122endfunc str_in_crash_buf_print 123 124 /* ------------------------------------------------------ 125 * This macro calculates the offset to crash buf from 126 * cpu_data and stores it in tpidr_el3. It also saves x0 127 * and x1 in the crash buf by using sp as a temporary 128 * register. 129 * ------------------------------------------------------ 130 */ 131 .macro prepare_crash_buf_save_x0_x1 132 /* we can corrupt this reg to free up x0 */ 133 mov sp, x0 134 /* tpidr_el3 contains the address to cpu_data structure */ 135 mrs x0, tpidr_el3 136 /* Calculate the Crash buffer offset in cpu_data */ 137 add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET 138 /* Store crash buffer address in tpidr_el3 */ 139 msr tpidr_el3, x0 140 str x1, [x0, #REG_SIZE] 141 mov x1, sp 142 str x1, [x0] 143 .endm 144 145 /* ----------------------------------------------------- 146 * This function allows to report a crash (if crash 147 * reporting is enabled) when an unhandled exception 148 * occurs. It prints the CPU state via the crash console 149 * making use of the crash buf. This function will 150 * not return. 151 * ----------------------------------------------------- 152 */ 153func report_unhandled_exception 154 prepare_crash_buf_save_x0_x1 155 adr x0, excpt_msg 156 mov sp, x0 157 /* This call will not return */ 158 b do_crash_reporting 159endfunc report_unhandled_exception 160 161 162 /* ----------------------------------------------------- 163 * This function allows to report a crash (if crash 164 * reporting is enabled) when an unhandled interrupt 165 * occurs. It prints the CPU state via the crash console 166 * making use of the crash buf. This function will 167 * not return. 168 * ----------------------------------------------------- 169 */ 170func report_unhandled_interrupt 171 prepare_crash_buf_save_x0_x1 172 adr x0, intr_excpt_msg 173 mov sp, x0 174 /* This call will not return */ 175 b do_crash_reporting 176endfunc report_unhandled_interrupt 177 178 /* ----------------------------------------------------- 179 * This function allows to report a crash (if crash 180 * reporting is enabled) when panic() is invoked from 181 * C Runtime. It prints the CPU state via the crash 182 * console making use of the crash buf. This function 183 * will not return. 184 * ----------------------------------------------------- 185 */ 186func el3_panic 187 msr spsel, #1 188 prepare_crash_buf_save_x0_x1 189 adr x0, panic_msg 190 mov sp, x0 191 /* This call will not return */ 192 b do_crash_reporting 193endfunc el3_panic 194 195 /* ------------------------------------------------------------ 196 * The common crash reporting functionality. It requires x0 197 * and x1 has already been stored in crash buf, sp points to 198 * crash message and tpidr_el3 contains the crash buf address. 199 * The function does the following: 200 * - Retrieve the crash buffer from tpidr_el3 201 * - Store x2 to x6 in the crash buffer 202 * - Initialise the crash console. 203 * - Print the crash message by using the address in sp. 204 * - Print x30 value to the crash console. 205 * - Print x0 - x7 from the crash buf to the crash console. 206 * - Print x8 - x29 (in groups of 8 registers) using the 207 * crash buf to the crash console. 208 * - Print el3 sys regs (in groups of 8 registers) using the 209 * crash buf to the crash console. 210 * - Print non el3 sys regs (in groups of 8 registers) using 211 * the crash buf to the crash console. 212 * ------------------------------------------------------------ 213 */ 214func do_crash_reporting 215 /* Retrieve the crash buf from tpidr_el3 */ 216 mrs x0, tpidr_el3 217 /* Store x2 - x6, x30 in the crash buffer */ 218 stp x2, x3, [x0, #REG_SIZE * 2] 219 stp x4, x5, [x0, #REG_SIZE * 4] 220 stp x6, x30, [x0, #REG_SIZE * 6] 221 /* Initialize the crash console */ 222 bl plat_crash_console_init 223 /* Verify the console is initialized */ 224 cbz x0, crash_panic 225 /* Print the crash message. sp points to the crash message */ 226 mov x4, sp 227 bl asm_print_str 228 /* load the crash buf address */ 229 mrs x0, tpidr_el3 230 /* report x30 first from the crash buf */ 231 ldr x4, [x0, #REG_SIZE * 7] 232 bl asm_print_hex 233 bl print_newline 234 /* Load the crash buf address */ 235 mrs x0, tpidr_el3 236 /* Now mov x7 into crash buf */ 237 str x7, [x0, #REG_SIZE * 7] 238 239 /* Report x0 - x29 values stored in crash buf*/ 240 /* Store the ascii list pointer in x6 */ 241 adr x6, gp_regs 242 /* Print x0 to x7 from the crash buf */ 243 bl size_controlled_print 244 /* Store x8 - x15 in crash buf and print */ 245 bl str_in_crash_buf_print 246 /* Load the crash buf address */ 247 mrs x0, tpidr_el3 248 /* Store the rest of gp regs and print */ 249 stp x16, x17, [x0] 250 stp x18, x19, [x0, #REG_SIZE * 2] 251 stp x20, x21, [x0, #REG_SIZE * 4] 252 stp x22, x23, [x0, #REG_SIZE * 6] 253 bl size_controlled_print 254 /* Load the crash buf address */ 255 mrs x0, tpidr_el3 256 stp x24, x25, [x0] 257 stp x26, x27, [x0, #REG_SIZE * 2] 258 stp x28, x29, [x0, #REG_SIZE * 4] 259 bl size_controlled_print 260 261 /* Print the el3 sys registers */ 262 adr x6, el3_sys_regs 263 mrs x8, scr_el3 264 mrs x9, sctlr_el3 265 mrs x10, cptr_el3 266 mrs x11, tcr_el3 267 mrs x12, daif 268 mrs x13, mair_el3 269 mrs x14, spsr_el3 270 mrs x15, elr_el3 271 bl str_in_crash_buf_print 272 mrs x8, ttbr0_el3 273 mrs x9, esr_el3 274 mrs x10, far_el3 275 bl str_in_crash_buf_print 276 277 /* Print the non el3 sys registers */ 278 adr x6, non_el3_sys_regs 279 mrs x8, spsr_el1 280 mrs x9, elr_el1 281 mrs x10, spsr_abt 282 mrs x11, spsr_und 283 mrs x12, spsr_irq 284 mrs x13, spsr_fiq 285 mrs x14, sctlr_el1 286 mrs x15, actlr_el1 287 bl str_in_crash_buf_print 288 mrs x8, cpacr_el1 289 mrs x9, csselr_el1 290 mrs x10, sp_el1 291 mrs x11, esr_el1 292 mrs x12, ttbr0_el1 293 mrs x13, ttbr1_el1 294 mrs x14, mair_el1 295 mrs x15, amair_el1 296 bl str_in_crash_buf_print 297 mrs x8, tcr_el1 298 mrs x9, tpidr_el1 299 mrs x10, tpidr_el0 300 mrs x11, tpidrro_el0 301 mrs x12, dacr32_el2 302 mrs x13, ifsr32_el2 303 mrs x14, par_el1 304 mrs x15, mpidr_el1 305 bl str_in_crash_buf_print 306 mrs x8, afsr0_el1 307 mrs x9, afsr1_el1 308 mrs x10, contextidr_el1 309 mrs x11, vbar_el1 310 mrs x12, cntp_ctl_el0 311 mrs x13, cntp_cval_el0 312 mrs x14, cntv_ctl_el0 313 mrs x15, cntv_cval_el0 314 bl str_in_crash_buf_print 315 mrs x8, cntkctl_el1 316 mrs x9, fpexc32_el2 317 mrs x10, sp_el0 318 mrs x11, isr_el1 319 bl str_in_crash_buf_print 320 321 /* Get the cpu specific registers to report */ 322 bl do_cpu_reg_dump 323 bl str_in_crash_buf_print 324 325 /* Print some platform registers */ 326 plat_crash_print_regs 327 328 bl plat_crash_console_flush 329 330 /* Done reporting */ 331 no_ret plat_panic_handler 332endfunc do_crash_reporting 333 334#else /* CRASH_REPORTING */ 335func report_unhandled_exception 336report_unhandled_interrupt: 337 no_ret plat_panic_handler 338endfunc report_unhandled_exception 339#endif /* CRASH_REPORTING */ 340 341 342func crash_panic 343 no_ret plat_panic_handler 344endfunc crash_panic 345