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_1: 45 .asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\ 46 "spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\ 47 "csselr_el1", "sp_el1", "esr_el1", "" 48 49ttbr_regs: 50 .asciz "ttbr0_el1", "ttbr0_el2", "ttbr1_el1", "vttbr_el2", "" 51 52non_el3_sys_regs_2: 53 .asciz "mair_el1", "amair_el1", "tcr_el1", "tpidr_el1",\ 54 "tpidr_el0", "tpidrro_el0", "" 55 56par_reg: 57 .asciz "par_el1", "" 58 59non_el3_sys_regs_3: 60 .asciz "mpidr_el1", "afsr0_el1", "afsr1_el1", "contextidr_el1",\ 61 "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0", "cntv_ctl_el0",\ 62 "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", "" 63 64#if CTX_INCLUDE_AARCH32_REGS 65aarch32_regs: 66 .asciz "dacr32_el2", "ifsr32_el2", "" 67#endif /* CTX_INCLUDE_AARCH32_REGS */ 68 69panic_msg: 70 .asciz "PANIC in EL3.\nx30" 71excpt_msg: 72 .asciz "Unhandled Exception in EL3.\nx30" 73intr_excpt_msg: 74 .ascii "Unhandled Interrupt Exception in EL3.\n" 75x30_msg: 76 .asciz "x30" 77excpt_msg_el: 78 .asciz "Unhandled Exception from lower EL.\n" 79 80 /* 81 * Helper function to print from crash buf. 82 * The print loop is controlled by the buf size and 83 * ascii reg name list which is passed in x6. The 84 * function returns the crash buf address in x0. 85 * Clobbers : x0 - x7, x20, sp 86 */ 87func size_controlled_print_helper 88#if ENABLE_FEAT_D128 89size_controlled_print_128: 90 /* Set flag to print 128-bit registers */ 91 mov x20, #1 92 b 1f 93 94size_controlled_print: 95 /* Set flag to print 64-bit registers */ 96 mov x20, #0 971: 98#else 99size_controlled_print: 100#endif 101 /* Save the lr */ 102 mov sp, x30 103 /* load the crash buf address */ 104 mrs x7, tpidr_el3 105test_size_list: 106 /* Calculate x5 always as it will be clobbered by asm_print_hex */ 107 mrs x5, tpidr_el3 108 add x5, x5, #CPU_DATA_CRASH_BUF_SIZE 109 /* Test whether we have reached end of crash buf */ 110 cmp x7, x5 111 b.eq exit_size_print 112 ldrb w4, [x6] 113 /* Test whether we are at end of list */ 114 cbz w4, exit_size_print 115 mov x4, x6 116 /* asm_print_str updates x4 to point to next entry in list */ 117 bl asm_print_str 118 /* x0 = number of symbols printed + 1 */ 119 sub x0, x4, x6 120 /* update x6 with the updated list pointer */ 121 mov x6, x4 122 bl print_alignment 123 /* Print the high 64 bits (or whole 64-bit register) */ 124 ldr x4, [x7], #REGSZ 125 bl asm_print_hex 126#if ENABLE_FEAT_D128 127 cbz x20, 2f 128 /* Print the low 64 bits in case of a 128-bit register */ 129 ldr x4, [x7], #REGSZ 130 bl asm_print_hex 1312: 132#endif 133 bl asm_print_newline 134 b test_size_list 135exit_size_print: 136 mov x30, sp 137 ret 138endfunc size_controlled_print_helper 139 140 /* ----------------------------------------------------- 141 * This function calculates and prints required number 142 * of space characters followed by "= 0x", based on the 143 * length of ascii register name. 144 * x0: length of ascii register name + 1 145 * ------------------------------------------------------ 146 */ 147func print_alignment 148 /* The minimum ascii length is 3, e.g. for "x0" */ 149 adr x4, print_spacer - 3 150 add x4, x4, x0 151 b asm_print_str 152endfunc print_alignment 153 154 /* 155 * Helper function to store x8 - x15 registers to 156 * the crash buf. The system registers values are 157 * copied to x8 to x15 by the caller which are then 158 * copied to the crash buf by this function. 159 * x0 points to the crash buf. It then calls 160 * size_controlled_print to print to console. 161 * Clobbers : x0 - x7, x20, sp 162 */ 163func str_in_crash_buf_print 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 171endfunc str_in_crash_buf_print 172 173 /* 174 * An equivalent helper function for storing x8 - x15 175 * registers in a different order inside the crash buf. 176 * In the end the function size_controlled_print_128 is 177 * called to print the registers to the console. 178 * Clobbers : x0 - x7, x20, sp 179 */ 180func str_in_crash_buf_print_128 181 /* restore the crash buf address in x0 */ 182 mrs x0, tpidr_el3 183 stp x8, x9, [x0] 184 stp x10, x11, [x0, #REGSZ * 2] 185 stp x12, x13, [x0, #REGSZ * 4] 186 stp x14, x15, [x0, #REGSZ * 6] 187 b size_controlled_print_128 188endfunc str_in_crash_buf_print_128 189 190 /* ------------------------------------------------------ 191 * This macro calculates the offset to crash buf from 192 * cpu_data and stores it in tpidr_el3. It also saves x0 193 * and x1 in the crash buf by using sp as a temporary 194 * register. 195 * ------------------------------------------------------ 196 */ 197 .macro prepare_crash_buf_save_x0_x1 198 /* we can corrupt this reg to free up x0 */ 199 mov sp, x0 200 /* tpidr_el3 contains the address to cpu_data structure */ 201 mrs x0, tpidr_el3 202 /* Calculate the Crash buffer offset in cpu_data */ 203 add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET 204 /* Store crash buffer address in tpidr_el3 */ 205 msr tpidr_el3, x0 206 str x1, [x0, #REGSZ] 207 mov x1, sp 208 str x1, [x0] 209 .endm 210 211 /* ----------------------------------------------------- 212 * This function allows to report a crash (if crash 213 * reporting is enabled) when an unhandled exception 214 * occurs. It prints the CPU state via the crash console 215 * making use of the crash buf. This function will 216 * not return. 217 * ----------------------------------------------------- 218 */ 219func report_unhandled_exception 220 prepare_crash_buf_save_x0_x1 221 adr x0, excpt_msg 222 mov sp, x0 223 /* This call will not return */ 224 b do_crash_reporting 225endfunc report_unhandled_exception 226 227 /* ----------------------------------------------------- 228 * This function allows to report a crash (if crash 229 * reporting is enabled) when an unhandled interrupt 230 * occurs. It prints the CPU state via the crash console 231 * making use of the crash buf. This function will 232 * not return. 233 * ----------------------------------------------------- 234 */ 235func report_unhandled_interrupt 236 prepare_crash_buf_save_x0_x1 237 adr x0, intr_excpt_msg 238 mov sp, x0 239 /* This call will not return */ 240 b do_crash_reporting 241endfunc report_unhandled_interrupt 242 243 /* ----------------------------------------------------- 244 * This function allows to report a crash from the lower 245 * exception level (if crash reporting is enabled) when 246 * lower_el_panic() is invoked from C Runtime. 247 * It prints the CPU state via the crash console making 248 * use of 'cpu_context' structure where general purpose 249 * registers are saved and the crash buf. 250 * This function will not return. 251 * ----------------------------------------------------- 252 */ 253func report_elx_panic 254 msr spsel, #MODE_SP_ELX 255 256 /* Print the crash message */ 257 adr x4, excpt_msg_el 258 bl asm_print_str 259 260 /* Report x0 - x29 values stored in 'gpregs_ctx' structure */ 261 /* Store the ascii list pointer in x6 */ 262 adr x6, gp_regs 263 add x7, sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0 264 265print_next: 266 ldrb w4, [x6] 267 /* Test whether we are at end of list */ 268 cbz w4, print_x30 269 mov x4, x6 270 /* asm_print_str updates x4 to point to next entry in list */ 271 bl asm_print_str 272 /* x0 = number of symbols printed + 1 */ 273 sub x0, x4, x6 274 /* Update x6 with the updated list pointer */ 275 mov x6, x4 276 bl print_alignment 277 ldr x4, [x7], #REGSZ 278 bl asm_print_hex 279 bl asm_print_newline 280 b print_next 281 282print_x30: 283 adr x4, x30_msg 284 bl asm_print_str 285 286 /* Print spaces to align "x30" string */ 287 mov x0, #4 288 bl print_alignment 289 290 /* Report x30 */ 291 ldr x4, [x7] 292 293 /* ---------------------------------------------------------------- 294 * Different virtual address space size can be defined for each EL. 295 * Ensure that we use the proper one by reading the corresponding 296 * TCR_ELx register. 297 * ---------------------------------------------------------------- 298 */ 299 cmp x8, #MODE_EL2 300 b.lt from_el1 /* EL1 */ 301 mrs x2, sctlr_el2 302 mrs x1, tcr_el2 303 304 /* ---------------------------------------------------------------- 305 * Check if pointer authentication is enabled at the specified EL. 306 * If it isn't, we can then skip stripping a PAC code. 307 * ---------------------------------------------------------------- 308 */ 309test_pauth: 310 tst x2, #(SCTLR_EnIA_BIT | SCTLR_EnIB_BIT) 311 b.eq no_pauth 312 313 /* Demangle address */ 314 and x1, x1, #0x3F /* T0SZ = TCR_ELx[5:0] */ 315 sub x1, x1, #64 316 neg x1, x1 /* bottom_pac_bit = 64 - T0SZ */ 317 mov x2, #-1 318 lsl x2, x2, x1 319 bic x4, x4, x2 320 321no_pauth: 322 bl asm_print_hex 323 bl asm_print_newline 324 325 /* tpidr_el3 contains the address to cpu_data structure */ 326 mrs x0, tpidr_el3 327 /* Calculate the Crash buffer offset in cpu_data */ 328 add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET 329 /* Store crash buffer address in tpidr_el3 */ 330 msr tpidr_el3, x0 331 332 /* Print the rest of crash dump */ 333 b print_el3_sys_regs 334 335from_el1: 336 mrs x2, sctlr_el1 337 mrs x1, tcr_el1 338 b test_pauth 339endfunc report_elx_panic 340 341 /* ----------------------------------------------------- 342 * This function allows to report a crash (if crash 343 * reporting is enabled) when panic() is invoked from 344 * C Runtime. It prints the CPU state via the crash 345 * console making use of the crash buf. This function 346 * will not return. 347 * ----------------------------------------------------- 348 */ 349func report_el3_panic 350 msr spsel, #MODE_SP_ELX 351 prepare_crash_buf_save_x0_x1 352 adr x0, panic_msg 353 mov sp, x0 354 /* Fall through to 'do_crash_reporting' */ 355 356 /* ------------------------------------------------------------ 357 * The common crash reporting functionality. It requires x0 358 * and x1 has already been stored in crash buf, sp points to 359 * crash message and tpidr_el3 contains the crash buf address. 360 * The function does the following: 361 * - Retrieve the crash buffer from tpidr_el3 362 * - Store x2 to x6 in the crash buffer 363 * - Initialise the crash console. 364 * - Print the crash message by using the address in sp. 365 * - Print x30 value to the crash console. 366 * - Print x0 - x7 from the crash buf to the crash console. 367 * - Print x8 - x29 (in groups of 8 registers) using the 368 * crash buf to the crash console. 369 * - Print el3 sys regs (in groups of 8 registers) using the 370 * crash buf to the crash console. 371 * - Print non el3 sys regs (in groups of 8 registers) using 372 * the crash buf to the crash console. A group may be 373 * interrupted in case a potential group of 128-bit 374 * sys regs needs to be printed. 375 * ------------------------------------------------------------ 376 */ 377do_crash_reporting: 378 /* Retrieve the crash buf from tpidr_el3 */ 379 mrs x0, tpidr_el3 380 /* Store x2 - x6, x30 in the crash buffer */ 381 stp x2, x3, [x0, #REGSZ * 2] 382 stp x4, x5, [x0, #REGSZ * 4] 383 stp x6, x30, [x0, #REGSZ * 6] 384 /* Initialize the crash console */ 385 bl plat_crash_console_init 386 /* Verify the console is initialized */ 387 cbz x0, crash_panic 388 /* Print the crash message. sp points to the crash message */ 389 mov x4, sp 390 bl asm_print_str 391 /* Print spaces to align "x30" string */ 392 mov x0, #4 393 bl print_alignment 394 /* Load the crash buf address */ 395 mrs x0, tpidr_el3 396 /* Report x30 first from the crash buf */ 397 ldr x4, [x0, #REGSZ * 7] 398 399#if ENABLE_PAUTH 400 /* Demangle address */ 401 xpaci x4 402#endif 403 bl asm_print_hex 404 bl asm_print_newline 405 /* Load the crash buf address */ 406 mrs x0, tpidr_el3 407 /* Now mov x7 into crash buf */ 408 str x7, [x0, #REGSZ * 7] 409 410 /* Report x0 - x29 values stored in crash buf */ 411 /* Store the ascii list pointer in x6 */ 412 adr x6, gp_regs 413 /* Print x0 to x7 from the crash buf */ 414 bl size_controlled_print 415 /* Store x8 - x15 in crash buf and print */ 416 bl str_in_crash_buf_print 417 /* Load the crash buf address */ 418 mrs x0, tpidr_el3 419 /* Store the rest of gp regs and print */ 420 stp x16, x17, [x0] 421 stp x18, x19, [x0, #REGSZ * 2] 422 stp x20, x21, [x0, #REGSZ * 4] 423 stp x22, x23, [x0, #REGSZ * 6] 424 bl size_controlled_print 425 /* Load the crash buf address */ 426 mrs x0, tpidr_el3 427 stp x24, x25, [x0] 428 stp x26, x27, [x0, #REGSZ * 2] 429 stp x28, x29, [x0, #REGSZ * 4] 430 bl size_controlled_print 431 432 /* Print the el3 sys registers */ 433print_el3_sys_regs: 434 adr x6, el3_sys_regs 435 mrs x8, scr_el3 436 mrs x9, sctlr_el3 437 mrs x10, cptr_el3 438 mrs x11, tcr_el3 439 mrs x12, daif 440 mrs x13, mair_el3 441 mrs x14, spsr_el3 442 mrs x15, elr_el3 443 bl str_in_crash_buf_print 444 mrs x8, ttbr0_el3 445 mrs x9, esr_el3 446 mrs x10, far_el3 447 bl str_in_crash_buf_print 448 449 /* Print the non el3 sys registers */ 450 adr x6, non_el3_sys_regs_1 451 mrs x8, spsr_el1 452 mrs x9, elr_el1 453 mrs x10, spsr_abt 454 mrs x11, spsr_und 455 mrs x12, spsr_irq 456 mrs x13, spsr_fiq 457 mrs x14, sctlr_el1 458 mrs x15, actlr_el1 459 bl str_in_crash_buf_print 460 mrs x8, cpacr_el1 461 mrs x9, csselr_el1 462 mrs x10, sp_el1 463 mrs x11, esr_el1 464 bl str_in_crash_buf_print 465 466 adr x6, ttbr_regs 467#if ENABLE_FEAT_D128 468 is_feat_sysreg128_present_asm x19 469 /* Fallback to 64-bit if FEAT_SYSREG128 is disabled */ 470 cbz x19, ttbr_regs_64_bit 471 bl read_ttbr0_el1 472 mov x8, x1 473 mov x9, x0 474 bl read_ttbr0_el2 475 mov x10, x1 476 mov x11, x0 477 bl read_ttbr1_el1 478 mov x12, x1 479 mov x13, x0 480 bl read_vttbr_el2 481 mov x14, x1 482 mov x15, x0 483 bl str_in_crash_buf_print_128 484 b 1f 485 486ttbr_regs_64_bit: 487#endif 488 mrs x8, ttbr0_el1 489 mrs x9, ttbr0_el2 490 mrs x10, ttbr1_el1 491 mrs x11, vttbr_el2 492 bl str_in_crash_buf_print 4931: 494 adr x6, non_el3_sys_regs_2 495 mrs x8, mair_el1 496 mrs x9, amair_el1 497 mrs x10, tcr_el1 498 mrs x11, tpidr_el1 499 mrs x12, tpidr_el0 500 mrs x13, tpidrro_el0 501 bl str_in_crash_buf_print 502 503 adr x6, par_reg 504#if ENABLE_FEAT_D128 505 /* Fallback to 64-bit if FEAT_SYSREG128 is disabled */ 506 cbz x19, par_reg_64_bit 507 bl read_par_el1 508 mov x8, x1 509 mov x9, x0 510 bl str_in_crash_buf_print_128 511 b 2f 512 513par_reg_64_bit: 514#endif 515 mrs x8, par_el1 516 bl str_in_crash_buf_print 5172: 518 adr x6, non_el3_sys_regs_3 519 mrs x8, mpidr_el1 520 mrs x9, afsr0_el1 521 mrs x10, afsr1_el1 522 mrs x11, contextidr_el1 523 mrs x12, vbar_el1 524 mrs x13, cntp_ctl_el0 525 mrs x14, cntp_cval_el0 526 mrs x15, cntv_ctl_el0 527 bl str_in_crash_buf_print 528 mrs x8, cntv_cval_el0 529 mrs x9, cntkctl_el1 530 mrs x10, sp_el0 531 mrs x11, isr_el1 532 bl str_in_crash_buf_print 533 534#if CTX_INCLUDE_AARCH32_REGS 535 /* Print the AArch32 registers */ 536 adr x6, aarch32_regs 537 mrs x8, dacr32_el2 538 mrs x9, ifsr32_el2 539 bl str_in_crash_buf_print 540#endif /* CTX_INCLUDE_AARCH32_REGS */ 541 542 /* Get the cpu specific registers to report */ 543 bl do_cpu_reg_dump 544 bl str_in_crash_buf_print 545 546 /* Print some platform registers */ 547 plat_crash_print_regs 548 549 bl plat_crash_console_flush 550 551 /* Done reporting */ 552 no_ret plat_panic_handler 553endfunc report_el3_panic 554 555#else /* CRASH_REPORTING */ 556func report_unhandled_exception 557report_unhandled_interrupt: 558 no_ret plat_panic_handler 559endfunc report_unhandled_exception 560#endif /* CRASH_REPORTING */ 561 562func crash_panic 563 no_ret plat_panic_handler 564endfunc crash_panic 565