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#if ENABLE_PAUTH == 2 401 /* Skip if not present in hardware */ 402 is_feat_pauth_present_asm x0, x1 403 beq 1f 404#endif 405 /* 406 * The assembler must see support for xpaci. So turn the compiler 407 * extension on. GCC prior to 10 doesn't understand the PAuth extension 408 * but it does understand armv8.3-a in general. Avoid using 8.3 if 409 * the compiler understands "pauth" so we don't downgrade a higher 410 * -march that was specified on the commandline. 411 */ 412#if __GNUC__ < 10 413 .arch armv8.3-a 414#else 415 .arch_extension pauth 416#endif 417 /* Demangle address */ 418 xpaci x4 4191: 420#endif 421 bl asm_print_hex 422 bl asm_print_newline 423 /* Load the crash buf address */ 424 mrs x0, tpidr_el3 425 /* Now mov x7 into crash buf */ 426 str x7, [x0, #REGSZ * 7] 427 428 /* Report x0 - x29 values stored in crash buf */ 429 /* Store the ascii list pointer in x6 */ 430 adr x6, gp_regs 431 /* Print x0 to x7 from the crash buf */ 432 bl size_controlled_print 433 /* Store x8 - x15 in crash buf and print */ 434 bl str_in_crash_buf_print 435 /* Load the crash buf address */ 436 mrs x0, tpidr_el3 437 /* Store the rest of gp regs and print */ 438 stp x16, x17, [x0] 439 stp x18, x19, [x0, #REGSZ * 2] 440 stp x20, x21, [x0, #REGSZ * 4] 441 stp x22, x23, [x0, #REGSZ * 6] 442 bl size_controlled_print 443 /* Load the crash buf address */ 444 mrs x0, tpidr_el3 445 stp x24, x25, [x0] 446 stp x26, x27, [x0, #REGSZ * 2] 447 stp x28, x29, [x0, #REGSZ * 4] 448 bl size_controlled_print 449 450 /* Print the el3 sys registers */ 451print_el3_sys_regs: 452 adr x6, el3_sys_regs 453 mrs x8, scr_el3 454 mrs x9, sctlr_el3 455 mrs x10, cptr_el3 456 mrs x11, tcr_el3 457 mrs x12, daif 458 mrs x13, mair_el3 459 mrs x14, spsr_el3 460 mrs x15, elr_el3 461 bl str_in_crash_buf_print 462 mrs x8, ttbr0_el3 463 mrs x9, esr_el3 464 mrs x10, far_el3 465 bl str_in_crash_buf_print 466 467 /* Print the non el3 sys registers */ 468 adr x6, non_el3_sys_regs_1 469 mrs x8, spsr_el1 470 mrs x9, elr_el1 471 mrs x10, spsr_abt 472 mrs x11, spsr_und 473 mrs x12, spsr_irq 474 mrs x13, spsr_fiq 475 mrs x14, sctlr_el1 476 mrs x15, actlr_el1 477 bl str_in_crash_buf_print 478 mrs x8, cpacr_el1 479 mrs x9, csselr_el1 480 mrs x10, sp_el1 481 mrs x11, esr_el1 482 bl str_in_crash_buf_print 483 484 adr x6, ttbr_regs 485#if ENABLE_FEAT_D128 486 is_feat_sysreg128_present_asm x19 487 /* Fallback to 64-bit if FEAT_SYSREG128 is disabled */ 488 cbz x19, ttbr_regs_64_bit 489 bl read_ttbr0_el1 490 mov x8, x1 491 mov x9, x0 492 bl read_ttbr0_el2 493 mov x10, x1 494 mov x11, x0 495 bl read_ttbr1_el1 496 mov x12, x1 497 mov x13, x0 498 bl read_vttbr_el2 499 mov x14, x1 500 mov x15, x0 501 bl str_in_crash_buf_print_128 502 b 1f 503 504ttbr_regs_64_bit: 505#endif 506 mrs x8, ttbr0_el1 507 mrs x9, ttbr0_el2 508 mrs x10, ttbr1_el1 509 mrs x11, vttbr_el2 510 bl str_in_crash_buf_print 5111: 512 adr x6, non_el3_sys_regs_2 513 mrs x8, mair_el1 514 mrs x9, amair_el1 515 mrs x10, tcr_el1 516 mrs x11, tpidr_el1 517 mrs x12, tpidr_el0 518 mrs x13, tpidrro_el0 519 bl str_in_crash_buf_print 520 521 adr x6, par_reg 522#if ENABLE_FEAT_D128 523 /* Fallback to 64-bit if FEAT_SYSREG128 is disabled */ 524 cbz x19, par_reg_64_bit 525 bl read_par_el1 526 mov x8, x1 527 mov x9, x0 528 bl str_in_crash_buf_print_128 529 b 2f 530 531par_reg_64_bit: 532#endif 533 mrs x8, par_el1 534 bl str_in_crash_buf_print 5352: 536 adr x6, non_el3_sys_regs_3 537 mrs x8, mpidr_el1 538 mrs x9, afsr0_el1 539 mrs x10, afsr1_el1 540 mrs x11, contextidr_el1 541 mrs x12, vbar_el1 542 mrs x13, cntp_ctl_el0 543 mrs x14, cntp_cval_el0 544 mrs x15, cntv_ctl_el0 545 bl str_in_crash_buf_print 546 mrs x8, cntv_cval_el0 547 mrs x9, cntkctl_el1 548 mrs x10, sp_el0 549 mrs x11, isr_el1 550 bl str_in_crash_buf_print 551 552#if CTX_INCLUDE_AARCH32_REGS 553 /* Print the AArch32 registers */ 554 adr x6, aarch32_regs 555 mrs x8, dacr32_el2 556 mrs x9, ifsr32_el2 557 bl str_in_crash_buf_print 558#endif /* CTX_INCLUDE_AARCH32_REGS */ 559 560 /* Get the cpu specific registers to report */ 561 bl do_cpu_reg_dump 562 bl str_in_crash_buf_print 563 564 /* Print some platform registers */ 565 plat_crash_print_regs 566 567 bl plat_crash_console_flush 568 569 /* Done reporting */ 570 no_ret plat_panic_handler 571endfunc report_el3_panic 572 573#else /* CRASH_REPORTING */ 574func report_unhandled_exception 575report_unhandled_interrupt: 576 no_ret plat_panic_handler 577endfunc report_unhandled_exception 578#endif /* CRASH_REPORTING */ 579 580func crash_panic 581 no_ret plat_panic_handler 582endfunc crash_panic 583