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