You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
478 lines
13 KiB
478 lines
13 KiB
/*
|
|
* Copyright (c) 2014-2020, 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 el3_panic
|
|
.globl 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 EL"
|
|
|
|
/*
|
|
* 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
|
|
* 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.
|
|
*
|
|
* x0: Exception level
|
|
* -----------------------------------------------------
|
|
*/
|
|
func elx_panic
|
|
msr spsel, #MODE_SP_ELX
|
|
mov x8, x0
|
|
|
|
/* Print the crash message */
|
|
adr x4, excpt_msg_el
|
|
bl asm_print_str
|
|
|
|
/* Print exception level */
|
|
add x0, x8, #'0'
|
|
bl plat_crash_console_putc
|
|
bl asm_print_newline
|
|
|
|
/* 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 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 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 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
|