1/* 2 * Copyright (c) 2014-2025, 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 report_el3_panic 19 .globl report_elx_panic 20 21#if CRASH_REPORTING 22 23 /* ------------------------------------------------------ 24 * The below section deals with dumping the system state 25 * when an unhandled exception is taken in EL3. 26 * The layout and the names of the registers which will 27 * be dumped during a unhandled exception is given below. 28 * ------------------------------------------------------ 29 */ 30.section .rodata.crash_prints, "aS" 31print_spacer: 32 .asciz " = 0x" 33 34gp_regs: 35 .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\ 36 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\ 37 "x16", "x17", "x18", "x19", "x20", "x21", "x22",\ 38 "x23", "x24", "x25", "x26", "x27", "x28", "x29", "" 39el3_sys_regs: 40 .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\ 41 "daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\ 42 "esr_el3", "far_el3", "" 43 44non_el3_sys_regs: 45 .asciz "mpidr_el1", "sp_el0", "isr_el1", "" 46 47#if CTX_INCLUDE_AARCH32_REGS 48aarch32_regs: 49 .asciz "dacr32_el2", "ifsr32_el2", "" 50#endif /* CTX_INCLUDE_AARCH32_REGS */ 51 52panic_msg: 53 .asciz "PANIC in EL3.\nx30" 54excpt_msg: 55 .asciz "Unhandled Exception in EL3.\nx30" 56intr_excpt_msg: 57 .ascii "Unhandled Interrupt Exception in EL3.\n" 58x30_msg: 59 .asciz "x30" 60excpt_msg_el: 61 .asciz "Unhandled Exception from lower EL.\n" 62 63 /* 64 * Helper function to print from crash buf. 65 * The print loop is controlled by the buf size and 66 * ascii reg name list which is passed in x6. The 67 * function returns the crash buf address in x0. 68 * Clobbers : x0 - x7, x20, sp 69 */ 70func size_controlled_print_helper 71#if ENABLE_FEAT_D128 72size_controlled_print_128: 73 /* Set flag to print 128-bit registers */ 74 mov x20, #1 75 b 1f 76 77size_controlled_print: 78 /* Set flag to print 64-bit registers */ 79 mov x20, #0 801: 81#else 82size_controlled_print: 83#endif 84 /* Save the lr */ 85 mov sp, x30 86 /* load the crash buf address */ 87 mrs x7, tpidr_el3 88test_size_list: 89 /* Calculate x5 always as it will be clobbered by asm_print_hex */ 90 mrs x5, tpidr_el3 91 add x5, x5, #CPU_DATA_CRASH_BUF_BYTES 92 /* Test whether we have reached end of crash buf */ 93 cmp x7, x5 94 b.eq exit_size_print 95 ldrb w4, [x6] 96 /* Test whether we are at end of list */ 97 cbz w4, exit_size_print 98 mov x4, x6 99 /* asm_print_str updates x4 to point to next entry in list */ 100 bl asm_print_str 101 /* x0 = number of symbols printed + 1 */ 102 sub x0, x4, x6 103 /* update x6 with the updated list pointer */ 104 mov x6, x4 105 bl print_alignment 106 /* Print the high 64 bits (or whole 64-bit register) */ 107 ldr x4, [x7], #REGSZ 108 bl asm_print_hex 109#if ENABLE_FEAT_D128 110 cbz x20, 2f 111 /* Print the low 64 bits in case of a 128-bit register */ 112 ldr x4, [x7], #REGSZ 113 bl asm_print_hex 1142: 115#endif 116 bl asm_print_newline 117 b test_size_list 118exit_size_print: 119 mov x30, sp 120 ret 121endfunc size_controlled_print_helper 122 123 /* ----------------------------------------------------- 124 * This function calculates and prints required number 125 * of space characters followed by "= 0x", based on the 126 * length of ascii register name. 127 * x0: length of ascii register name + 1 128 * ------------------------------------------------------ 129 */ 130func print_alignment 131 /* The minimum ascii length is 3, e.g. for "x0" */ 132 adr x4, print_spacer - 3 133 add x4, x4, x0 134 b asm_print_str 135endfunc print_alignment 136 137 /* 138 * Helper function to store x8 - x15 registers to 139 * the crash buf. The system registers values are 140 * copied to x8 to x15 by the caller which are then 141 * copied to the crash buf by this function. 142 * x0 points to the crash buf. It then calls 143 * size_controlled_print to print to console. 144 * Clobbers : x0 - x7, x20, sp 145 */ 146func str_in_crash_buf_print 147 /* restore the crash buf address in x0 */ 148 mrs x0, tpidr_el3 149 stp x8, x9, [x0] 150 stp x10, x11, [x0, #REGSZ * 2] 151 stp x12, x13, [x0, #REGSZ * 4] 152 stp x14, x15, [x0, #REGSZ * 6] 153 b size_controlled_print 154endfunc str_in_crash_buf_print 155 156 /* 157 * An equivalent helper function for storing x8 - x15 158 * registers in a different order inside the crash buf. 159 * In the end the function size_controlled_print_128 is 160 * called to print the registers to the console. 161 * Clobbers : x0 - x7, x20, sp 162 */ 163func str_in_crash_buf_print_128 164 /* restore the crash buf address in x0 */ 165 mrs x0, tpidr_el3 166 stp x8, x9, [x0] 167 stp x10, x11, [x0, #REGSZ * 2] 168 stp x12, x13, [x0, #REGSZ * 4] 169 stp x14, x15, [x0, #REGSZ * 6] 170 b size_controlled_print_128 171endfunc str_in_crash_buf_print_128 172 173 /* ------------------------------------------------------ 174 * This macro calculates the offset to crash buf from 175 * cpu_data and stores it in tpidr_el3. It also saves x0 176 * and x1 in the crash buf by using sp as a temporary 177 * register. 178 * ------------------------------------------------------ 179 */ 180 .macro prepare_crash_buf_save_x0_x1 181 /* we can corrupt this reg to free up x0 */ 182 mov sp, x0 183 /* tpidr_el3 contains the address to cpu_data structure */ 184 mrs x0, tpidr_el3 185 /* Calculate the Crash buffer offset in cpu_data */ 186 add x0, x0, #CPU_DATA_CRASH_BUF 187 /* Store crash buffer address in tpidr_el3 */ 188 msr tpidr_el3, x0 189 str x1, [x0, #REGSZ] 190 mov x1, sp 191 str x1, [x0] 192 .endm 193 194 /* ----------------------------------------------------- 195 * This function allows to report a crash (if crash 196 * reporting is enabled) when an unhandled exception 197 * occurs. It prints the CPU state via the crash console 198 * making use of the crash buf. This function will 199 * not return. 200 * ----------------------------------------------------- 201 */ 202func report_unhandled_exception 203 prepare_crash_buf_save_x0_x1 204 adr x0, excpt_msg 205 mov sp, x0 206 /* This call will not return */ 207 b do_crash_reporting 208endfunc report_unhandled_exception 209 210 /* ----------------------------------------------------- 211 * This function allows to report a crash (if crash 212 * reporting is enabled) when an unhandled interrupt 213 * occurs. It prints the CPU state via the crash console 214 * making use of the crash buf. This function will 215 * not return. 216 * ----------------------------------------------------- 217 */ 218func report_unhandled_interrupt 219 prepare_crash_buf_save_x0_x1 220 adr x0, intr_excpt_msg 221 mov sp, x0 222 /* This call will not return */ 223 b do_crash_reporting 224endfunc report_unhandled_interrupt 225 226 /* ----------------------------------------------------- 227 * This function allows to report a crash from the lower 228 * exception level (if crash reporting is enabled) when 229 * lower_el_panic() is invoked from C Runtime. 230 * It prints the CPU state via the crash console making 231 * use of 'cpu_context' structure where general purpose 232 * registers are saved and the crash buf. 233 * This function will not return. 234 * ----------------------------------------------------- 235 */ 236func report_elx_panic 237 msr spsel, #MODE_SP_ELX 238 239 /* Print the crash message */ 240 adr x4, excpt_msg_el 241 bl asm_print_str 242 243 /* Report x0 - x29 values stored in 'gpregs_ctx' structure */ 244 /* Store the ascii list pointer in x6 */ 245 adr x6, gp_regs 246 add x7, sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0 247 248print_next: 249 ldrb w4, [x6] 250 /* Test whether we are at end of list */ 251 cbz w4, print_x30 252 mov x4, x6 253 /* asm_print_str updates x4 to point to next entry in list */ 254 bl asm_print_str 255 /* x0 = number of symbols printed + 1 */ 256 sub x0, x4, x6 257 /* Update x6 with the updated list pointer */ 258 mov x6, x4 259 bl print_alignment 260 ldr x4, [x7], #REGSZ 261 bl asm_print_hex 262 bl asm_print_newline 263 b print_next 264 265print_x30: 266 adr x4, x30_msg 267 bl asm_print_str 268 269 /* Print spaces to align "x30" string */ 270 mov x0, #4 271 bl print_alignment 272 273 /* Report x30 */ 274 ldr x4, [x7] 275 276 /* ---------------------------------------------------------------- 277 * Different virtual address space size can be defined for each EL. 278 * Ensure that we use the proper one by reading the corresponding 279 * TCR_ELx register. 280 * ---------------------------------------------------------------- 281 */ 282 cmp x8, #MODE_EL2 283 b.lt from_el1 /* EL1 */ 284 mrs x2, sctlr_el2 285 mrs x1, tcr_el2 286 287 /* ---------------------------------------------------------------- 288 * Check if pointer authentication is enabled at the specified EL. 289 * If it isn't, we can then skip stripping a PAC code. 290 * ---------------------------------------------------------------- 291 */ 292test_pauth: 293 tst x2, #(SCTLR_EnIA_BIT | SCTLR_EnIB_BIT) 294 b.eq no_pauth 295 296 /* Demangle address */ 297 and x1, x1, #0x3F /* T0SZ = TCR_ELx[5:0] */ 298 sub x1, x1, #64 299 neg x1, x1 /* bottom_pac_bit = 64 - T0SZ */ 300 mov x2, #-1 301 lsl x2, x2, x1 302 bic x4, x4, x2 303 304no_pauth: 305 bl asm_print_hex 306 bl asm_print_newline 307 308 /* tpidr_el3 contains the address to cpu_data structure */ 309 mrs x0, tpidr_el3 310 /* Calculate the Crash buffer offset in cpu_data */ 311 add x0, x0, #CPU_DATA_CRASH_BUF 312 /* Store crash buffer address in tpidr_el3 */ 313 msr tpidr_el3, x0 314 315 /* Print the rest of crash dump */ 316 b print_el3_sys_regs 317 318from_el1: 319 mrs x2, sctlr_el1 320 mrs x1, tcr_el1 321 b test_pauth 322endfunc report_elx_panic 323 324 /* ----------------------------------------------------- 325 * This function allows to report a crash (if crash 326 * reporting is enabled) when panic() is invoked from 327 * C Runtime. It prints the CPU state via the crash 328 * console making use of the crash buf. This function 329 * will not return. 330 * ----------------------------------------------------- 331 */ 332func report_el3_panic 333 msr spsel, #MODE_SP_ELX 334 prepare_crash_buf_save_x0_x1 335 adr x0, panic_msg 336 mov sp, x0 337 /* Fall through to 'do_crash_reporting' */ 338 339 /* ------------------------------------------------------------ 340 * The common crash reporting functionality. It requires x0 341 * and x1 has already been stored in crash buf, sp points to 342 * crash message and tpidr_el3 contains the crash buf address. 343 * The function does the following: 344 * - Retrieve the crash buffer from tpidr_el3 345 * - Store x2 to x6 in the crash buffer 346 * - Initialise the crash console. 347 * - Print the crash message by using the address in sp. 348 * - Print x30 value to the crash console. 349 * - Print x0 - x7 from the crash buf to the crash console. 350 * - Print x8 - x29 (in groups of 8 registers) using the 351 * crash buf to the crash console. 352 * - Print el3 sys regs (in groups of 8 registers) using the 353 * crash buf to the crash console. 354 * - Print non el3 sys regs (in groups of 8 registers) using 355 * the crash buf to the crash console. A group may be 356 * interrupted in case a potential group of 128-bit 357 * sys regs needs to be printed. 358 * ------------------------------------------------------------ 359 */ 360do_crash_reporting: 361 /* Retrieve the crash buf from tpidr_el3 */ 362 mrs x0, tpidr_el3 363 /* Store x2 - x6, x30 in the crash buffer */ 364 stp x2, x3, [x0, #REGSZ * 2] 365 stp x4, x5, [x0, #REGSZ * 4] 366 stp x6, x30, [x0, #REGSZ * 6] 367 /* Initialize the crash console */ 368 bl plat_crash_console_init 369 /* Verify the console is initialized */ 370 cbz x0, crash_panic 371 /* Print the crash message. sp points to the crash message */ 372 mov x4, sp 373 bl asm_print_str 374 /* Print spaces to align "x30" string */ 375 mov x0, #4 376 bl print_alignment 377 /* Load the crash buf address */ 378 mrs x0, tpidr_el3 379 /* Report x30 first from the crash buf */ 380 ldr x4, [x0, #REGSZ * 7] 381 382#if ENABLE_PAUTH 383#if ENABLE_PAUTH == 2 384 /* Skip if not present in hardware */ 385 is_feat_pauth_present_asm x0, x1 386 beq 1f 387#endif 388 /* 389 * The assembler must see support for xpaci. So turn the compiler 390 * extension on. GCC prior to 10 doesn't understand the PAuth extension 391 * but it does understand armv8.3-a in general. Avoid using 8.3 if 392 * the compiler understands "pauth" so we don't downgrade a higher 393 * -march that was specified on the commandline. 394 */ 395#if __GNUC__ < 10 396 .arch armv8.3-a 397#else 398 .arch_extension pauth 399#endif 400 /* Demangle address */ 401 xpaci x4 4021: 403#endif 404 bl asm_print_hex 405 bl asm_print_newline 406 /* Load the crash buf address */ 407 mrs x0, tpidr_el3 408 /* Now mov x7 into crash buf */ 409 str x7, [x0, #REGSZ * 7] 410 411 /* Report x0 - x29 values stored in crash buf */ 412 /* Store the ascii list pointer in x6 */ 413 adr x6, gp_regs 414 /* Print x0 to x7 from the crash buf */ 415 bl size_controlled_print 416 /* Store x8 - x15 in crash buf and print */ 417 bl str_in_crash_buf_print 418 /* Load the crash buf address */ 419 mrs x0, tpidr_el3 420 /* Store the rest of gp regs and print */ 421 stp x16, x17, [x0] 422 stp x18, x19, [x0, #REGSZ * 2] 423 stp x20, x21, [x0, #REGSZ * 4] 424 stp x22, x23, [x0, #REGSZ * 6] 425 bl size_controlled_print 426 /* Load the crash buf address */ 427 mrs x0, tpidr_el3 428 stp x24, x25, [x0] 429 stp x26, x27, [x0, #REGSZ * 2] 430 stp x28, x29, [x0, #REGSZ * 4] 431 bl size_controlled_print 432 433 /* Print the el3 sys registers */ 434print_el3_sys_regs: 435 adr x6, el3_sys_regs 436 mrs x8, scr_el3 437 mrs x9, sctlr_el3 438 mrs x10, cptr_el3 439 mrs x11, tcr_el3 440 mrs x12, daif 441 mrs x13, mair_el3 442 mrs x14, spsr_el3 443 mrs x15, elr_el3 444 bl str_in_crash_buf_print 445 mrs x8, ttbr0_el3 446 mrs x9, esr_el3 447 mrs x10, far_el3 448 bl str_in_crash_buf_print 449 450 /* Print the non el3 sys registers */ 451 adr x6, non_el3_sys_regs 452 mrs x8, mpidr_el1 453 mrs x9, sp_el0 454 mrs x10, isr_el1 455 bl str_in_crash_buf_print 456 457#if CTX_INCLUDE_AARCH32_REGS 458 /* Print the AArch32 registers */ 459 adr x6, aarch32_regs 460 mrs x8, dacr32_el2 461 mrs x9, ifsr32_el2 462 bl str_in_crash_buf_print 463#endif /* CTX_INCLUDE_AARCH32_REGS */ 464 465 /* Get the cpu specific registers to report */ 466 bl do_cpu_reg_dump 467 bl str_in_crash_buf_print 468 469 /* Print some platform registers */ 470 plat_crash_print_regs 471 472 bl plat_crash_console_flush 473 474 /* Done reporting */ 475 no_ret plat_panic_handler 476endfunc report_el3_panic 477 478#else /* CRASH_REPORTING */ 479func report_unhandled_exception 480report_unhandled_interrupt: 481 no_ret plat_panic_handler 482endfunc report_unhandled_exception 483#endif /* CRASH_REPORTING */ 484 485func crash_panic 486 no_ret plat_panic_handler 487endfunc crash_panic 488