123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- /*
- * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <plat_macros.S>
- #include <platform_def.h>
- #include <arch.h>
- #include <asm_macros.S>
- #include <context.h>
- #include <lib/el3_runtime/cpu_data.h>
- #include <lib/utils_def.h>
- .globl report_unhandled_exception
- .globl report_unhandled_interrupt
- .globl report_el3_panic
- .globl report_elx_panic
- #if CRASH_REPORTING
- /* ------------------------------------------------------
- * The below section deals with dumping the system state
- * when an unhandled exception is taken in EL3.
- * The layout and the names of the registers which will
- * be dumped during a unhandled exception is given below.
- * ------------------------------------------------------
- */
- .section .rodata.crash_prints, "aS"
- print_spacer:
- .asciz " = 0x"
- gp_regs:
- .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
- "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
- "x16", "x17", "x18", "x19", "x20", "x21", "x22",\
- "x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
- el3_sys_regs:
- .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
- "daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\
- "esr_el3", "far_el3", ""
- non_el3_sys_regs:
- .asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\
- "spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\
- "csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\
- "mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\
- "tpidrro_el0", "par_el1", "mpidr_el1", "afsr0_el1", "afsr1_el1",\
- "contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\
- "cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", ""
- #if CTX_INCLUDE_AARCH32_REGS
- aarch32_regs:
- .asciz "dacr32_el2", "ifsr32_el2", ""
- #endif /* CTX_INCLUDE_AARCH32_REGS */
- panic_msg:
- .asciz "PANIC in EL3.\nx30"
- excpt_msg:
- .asciz "Unhandled Exception in EL3.\nx30"
- intr_excpt_msg:
- .ascii "Unhandled Interrupt Exception in EL3.\n"
- x30_msg:
- .asciz "x30"
- excpt_msg_el:
- .asciz "Unhandled Exception from lower EL.\n"
- /*
- * Helper function to print from crash buf.
- * The print loop is controlled by the buf size and
- * ascii reg name list which is passed in x6. The
- * function returns the crash buf address in x0.
- * Clobbers : x0 - x7, sp
- */
- func size_controlled_print
- /* Save the lr */
- mov sp, x30
- /* load the crash buf address */
- mrs x7, tpidr_el3
- test_size_list:
- /* Calculate x5 always as it will be clobbered by asm_print_hex */
- mrs x5, tpidr_el3
- add x5, x5, #CPU_DATA_CRASH_BUF_SIZE
- /* Test whether we have reached end of crash buf */
- cmp x7, x5
- b.eq exit_size_print
- ldrb w4, [x6]
- /* Test whether we are at end of list */
- cbz w4, exit_size_print
- mov x4, x6
- /* asm_print_str updates x4 to point to next entry in list */
- bl asm_print_str
- /* x0 = number of symbols printed + 1 */
- sub x0, x4, x6
- /* update x6 with the updated list pointer */
- mov x6, x4
- bl print_alignment
- ldr x4, [x7], #REGSZ
- bl asm_print_hex
- bl asm_print_newline
- b test_size_list
- exit_size_print:
- mov x30, sp
- ret
- endfunc size_controlled_print
- /* -----------------------------------------------------
- * This function calculates and prints required number
- * of space characters followed by "= 0x", based on the
- * length of ascii register name.
- * x0: length of ascii register name + 1
- * ------------------------------------------------------
- */
- func print_alignment
- /* The minimum ascii length is 3, e.g. for "x0" */
- adr x4, print_spacer - 3
- add x4, x4, x0
- b asm_print_str
- endfunc print_alignment
- /*
- * Helper function to store x8 - x15 registers to
- * the crash buf. The system registers values are
- * copied to x8 to x15 by the caller which are then
- * copied to the crash buf by this function.
- * x0 points to the crash buf. It then calls
- * size_controlled_print to print to console.
- * Clobbers : x0 - x7, sp
- */
- func str_in_crash_buf_print
- /* restore the crash buf address in x0 */
- mrs x0, tpidr_el3
- stp x8, x9, [x0]
- stp x10, x11, [x0, #REGSZ * 2]
- stp x12, x13, [x0, #REGSZ * 4]
- stp x14, x15, [x0, #REGSZ * 6]
- b size_controlled_print
- endfunc str_in_crash_buf_print
- /* ------------------------------------------------------
- * This macro calculates the offset to crash buf from
- * cpu_data and stores it in tpidr_el3. It also saves x0
- * and x1 in the crash buf by using sp as a temporary
- * register.
- * ------------------------------------------------------
- */
- .macro prepare_crash_buf_save_x0_x1
- /* we can corrupt this reg to free up x0 */
- mov sp, x0
- /* tpidr_el3 contains the address to cpu_data structure */
- mrs x0, tpidr_el3
- /* Calculate the Crash buffer offset in cpu_data */
- add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
- /* Store crash buffer address in tpidr_el3 */
- msr tpidr_el3, x0
- str x1, [x0, #REGSZ]
- mov x1, sp
- str x1, [x0]
- .endm
- /* -----------------------------------------------------
- * This function allows to report a crash (if crash
- * reporting is enabled) when an unhandled exception
- * occurs. It prints the CPU state via the crash console
- * making use of the crash buf. This function will
- * not return.
- * -----------------------------------------------------
- */
- func report_unhandled_exception
- prepare_crash_buf_save_x0_x1
- adr x0, excpt_msg
- mov sp, x0
- /* This call will not return */
- b do_crash_reporting
- endfunc report_unhandled_exception
- /* -----------------------------------------------------
- * This function allows to report a crash (if crash
- * reporting is enabled) when an unhandled interrupt
- * occurs. It prints the CPU state via the crash console
- * making use of the crash buf. This function will
- * not return.
- * -----------------------------------------------------
- */
- func report_unhandled_interrupt
- prepare_crash_buf_save_x0_x1
- adr x0, intr_excpt_msg
- mov sp, x0
- /* This call will not return */
- b do_crash_reporting
- endfunc report_unhandled_interrupt
- /* -----------------------------------------------------
- * This function allows to report a crash from the lower
- * exception level (if crash reporting is enabled) when
- * lower_el_panic() is invoked from C Runtime.
- * It prints the CPU state via the crash console making
- * use of 'cpu_context' structure where general purpose
- * registers are saved and the crash buf.
- * This function will not return.
- * -----------------------------------------------------
- */
- func report_elx_panic
- msr spsel, #MODE_SP_ELX
- /* Print the crash message */
- adr x4, excpt_msg_el
- bl asm_print_str
- /* Report x0 - x29 values stored in 'gpregs_ctx' structure */
- /* Store the ascii list pointer in x6 */
- adr x6, gp_regs
- add x7, sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0
- print_next:
- ldrb w4, [x6]
- /* Test whether we are at end of list */
- cbz w4, print_x30
- mov x4, x6
- /* asm_print_str updates x4 to point to next entry in list */
- bl asm_print_str
- /* x0 = number of symbols printed + 1 */
- sub x0, x4, x6
- /* Update x6 with the updated list pointer */
- mov x6, x4
- bl print_alignment
- ldr x4, [x7], #REGSZ
- bl asm_print_hex
- bl asm_print_newline
- b print_next
- print_x30:
- adr x4, x30_msg
- bl asm_print_str
- /* Print spaces to align "x30" string */
- mov x0, #4
- bl print_alignment
- /* Report x30 */
- ldr x4, [x7]
- /* ----------------------------------------------------------------
- * Different virtual address space size can be defined for each EL.
- * Ensure that we use the proper one by reading the corresponding
- * TCR_ELx register.
- * ----------------------------------------------------------------
- */
- cmp x8, #MODE_EL2
- b.lt from_el1 /* EL1 */
- mrs x2, sctlr_el2
- mrs x1, tcr_el2
- /* ----------------------------------------------------------------
- * Check if pointer authentication is enabled at the specified EL.
- * If it isn't, we can then skip stripping a PAC code.
- * ----------------------------------------------------------------
- */
- test_pauth:
- tst x2, #(SCTLR_EnIA_BIT | SCTLR_EnIB_BIT)
- b.eq no_pauth
- /* Demangle address */
- and x1, x1, #0x3F /* T0SZ = TCR_ELx[5:0] */
- sub x1, x1, #64
- neg x1, x1 /* bottom_pac_bit = 64 - T0SZ */
- mov x2, #-1
- lsl x2, x2, x1
- bic x4, x4, x2
- no_pauth:
- bl asm_print_hex
- bl asm_print_newline
- /* tpidr_el3 contains the address to cpu_data structure */
- mrs x0, tpidr_el3
- /* Calculate the Crash buffer offset in cpu_data */
- add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
- /* Store crash buffer address in tpidr_el3 */
- msr tpidr_el3, x0
- /* Print the rest of crash dump */
- b print_el3_sys_regs
- from_el1:
- mrs x2, sctlr_el1
- mrs x1, tcr_el1
- b test_pauth
- endfunc report_elx_panic
- /* -----------------------------------------------------
- * This function allows to report a crash (if crash
- * reporting is enabled) when panic() is invoked from
- * C Runtime. It prints the CPU state via the crash
- * console making use of the crash buf. This function
- * will not return.
- * -----------------------------------------------------
- */
- func report_el3_panic
- msr spsel, #MODE_SP_ELX
- prepare_crash_buf_save_x0_x1
- adr x0, panic_msg
- mov sp, x0
- /* Fall through to 'do_crash_reporting' */
- /* ------------------------------------------------------------
- * The common crash reporting functionality. It requires x0
- * and x1 has already been stored in crash buf, sp points to
- * crash message and tpidr_el3 contains the crash buf address.
- * The function does the following:
- * - Retrieve the crash buffer from tpidr_el3
- * - Store x2 to x6 in the crash buffer
- * - Initialise the crash console.
- * - Print the crash message by using the address in sp.
- * - Print x30 value to the crash console.
- * - Print x0 - x7 from the crash buf to the crash console.
- * - Print x8 - x29 (in groups of 8 registers) using the
- * crash buf to the crash console.
- * - Print el3 sys regs (in groups of 8 registers) using the
- * crash buf to the crash console.
- * - Print non el3 sys regs (in groups of 8 registers) using
- * the crash buf to the crash console.
- * ------------------------------------------------------------
- */
- do_crash_reporting:
- /* Retrieve the crash buf from tpidr_el3 */
- mrs x0, tpidr_el3
- /* Store x2 - x6, x30 in the crash buffer */
- stp x2, x3, [x0, #REGSZ * 2]
- stp x4, x5, [x0, #REGSZ * 4]
- stp x6, x30, [x0, #REGSZ * 6]
- /* Initialize the crash console */
- bl plat_crash_console_init
- /* Verify the console is initialized */
- cbz x0, crash_panic
- /* Print the crash message. sp points to the crash message */
- mov x4, sp
- bl asm_print_str
- /* Print spaces to align "x30" string */
- mov x0, #4
- bl print_alignment
- /* Load the crash buf address */
- mrs x0, tpidr_el3
- /* Report x30 first from the crash buf */
- ldr x4, [x0, #REGSZ * 7]
- #if ENABLE_PAUTH
- /* Demangle address */
- xpaci x4
- #endif
- bl asm_print_hex
- bl asm_print_newline
- /* Load the crash buf address */
- mrs x0, tpidr_el3
- /* Now mov x7 into crash buf */
- str x7, [x0, #REGSZ * 7]
- /* Report x0 - x29 values stored in crash buf */
- /* Store the ascii list pointer in x6 */
- adr x6, gp_regs
- /* Print x0 to x7 from the crash buf */
- bl size_controlled_print
- /* Store x8 - x15 in crash buf and print */
- bl str_in_crash_buf_print
- /* Load the crash buf address */
- mrs x0, tpidr_el3
- /* Store the rest of gp regs and print */
- stp x16, x17, [x0]
- stp x18, x19, [x0, #REGSZ * 2]
- stp x20, x21, [x0, #REGSZ * 4]
- stp x22, x23, [x0, #REGSZ * 6]
- bl size_controlled_print
- /* Load the crash buf address */
- mrs x0, tpidr_el3
- stp x24, x25, [x0]
- stp x26, x27, [x0, #REGSZ * 2]
- stp x28, x29, [x0, #REGSZ * 4]
- bl size_controlled_print
- /* Print the el3 sys registers */
- print_el3_sys_regs:
- adr x6, el3_sys_regs
- mrs x8, scr_el3
- mrs x9, sctlr_el3
- mrs x10, cptr_el3
- mrs x11, tcr_el3
- mrs x12, daif
- mrs x13, mair_el3
- mrs x14, spsr_el3
- mrs x15, elr_el3
- bl str_in_crash_buf_print
- mrs x8, ttbr0_el3
- mrs x9, esr_el3
- mrs x10, far_el3
- bl str_in_crash_buf_print
- /* Print the non el3 sys registers */
- adr x6, non_el3_sys_regs
- mrs x8, spsr_el1
- mrs x9, elr_el1
- mrs x10, spsr_abt
- mrs x11, spsr_und
- mrs x12, spsr_irq
- mrs x13, spsr_fiq
- mrs x14, sctlr_el1
- mrs x15, actlr_el1
- bl str_in_crash_buf_print
- mrs x8, cpacr_el1
- mrs x9, csselr_el1
- mrs x10, sp_el1
- mrs x11, esr_el1
- mrs x12, ttbr0_el1
- mrs x13, ttbr1_el1
- mrs x14, mair_el1
- mrs x15, amair_el1
- bl str_in_crash_buf_print
- mrs x8, tcr_el1
- mrs x9, tpidr_el1
- mrs x10, tpidr_el0
- mrs x11, tpidrro_el0
- mrs x12, par_el1
- mrs x13, mpidr_el1
- mrs x14, afsr0_el1
- mrs x15, afsr1_el1
- bl str_in_crash_buf_print
- mrs x8, contextidr_el1
- mrs x9, vbar_el1
- mrs x10, cntp_ctl_el0
- mrs x11, cntp_cval_el0
- mrs x12, cntv_ctl_el0
- mrs x13, cntv_cval_el0
- mrs x14, cntkctl_el1
- mrs x15, sp_el0
- bl str_in_crash_buf_print
- mrs x8, isr_el1
- bl str_in_crash_buf_print
- #if CTX_INCLUDE_AARCH32_REGS
- /* Print the AArch32 registers */
- adr x6, aarch32_regs
- mrs x8, dacr32_el2
- mrs x9, ifsr32_el2
- bl str_in_crash_buf_print
- #endif /* CTX_INCLUDE_AARCH32_REGS */
- /* Get the cpu specific registers to report */
- bl do_cpu_reg_dump
- bl str_in_crash_buf_print
- /* Print some platform registers */
- plat_crash_print_regs
- bl plat_crash_console_flush
- /* Done reporting */
- no_ret plat_panic_handler
- endfunc report_el3_panic
- #else /* CRASH_REPORTING */
- func report_unhandled_exception
- report_unhandled_interrupt:
- no_ret plat_panic_handler
- endfunc report_unhandled_exception
- #endif /* CRASH_REPORTING */
- func crash_panic
- no_ret plat_panic_handler
- endfunc crash_panic
|