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