Rework the crash reporting in BL3-1 to use less stack

This patch reworks the crash reporting mechanism to further
optimise the stack and code size. The reporting makes use
of assembly console functions to avoid calling C Runtime
to report the CPU state. The crash buffer requirement is
reduced to 64 bytes with this implementation. The crash
buffer is now part of per-cpu data which makes retrieving
the crash buffer trivial.

Also now panic() will use crash reporting if
invoked from BL3-1.

Fixes ARM-software/tf-issues#199

Change-Id: I79d27a4524583d723483165dc40801f45e627da5
This commit is contained in:
Soby Mathew 2014-06-25 10:07:40 +01:00
parent bc9201289c
commit 626ed510f1
10 changed files with 410 additions and 402 deletions

View File

@ -92,9 +92,8 @@ endif
VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING}
BL_COMMON_SOURCES := common/bl_common.c \
common/debug.c \
common/tf_printf.c \
common/aarch64/assert.S \
common/aarch64/debug.S \
lib/aarch64/cache_helpers.S \
lib/aarch64/misc_helpers.S \
lib/aarch64/xlat_helpers.c \

View File

@ -72,13 +72,22 @@ func bl31_entrypoint
isb
/* ---------------------------------------------
* Set the exception vector and zero tpidr_el3
* until the crash reporting is set up
* Initialise cpu_data early to enable crash
* reporting to have access to crash stack.
* Since crash reporting depends on cpu_data to
* report the unhandled exception, not
* doing so can lead to recursive exceptions due
* to a NULL TPIDR_EL3
* ---------------------------------------------
*/
bl init_cpu_data_ptr
/* ---------------------------------------------
* Set the exception vector.
* ---------------------------------------------
*/
adr x1, runtime_exceptions
msr vbar_el3, x1
msr tpidr_el3, xzr
/* ---------------------------------------------------------------------
* The initial state of the Architectural feature trap register
@ -136,15 +145,6 @@ func bl31_entrypoint
ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__
bl zeromem16
/* ---------------------------------------------
* Initialise cpu_data and crash reporting
* ---------------------------------------------
*/
#if CRASH_REPORTING
bl init_crash_reporting
#endif
bl init_cpu_data_ptr
/* ---------------------------------------------
* Use SP_EL0 for the C runtime stack.
* ---------------------------------------------

View File

@ -34,11 +34,13 @@
#include <plat_macros.S>
#include <platform_def.h>
.globl dump_state_and_die
.globl dump_intr_state_and_die
.globl init_crash_reporting
.globl report_unhandled_exception
.globl report_unhandled_interrupt
.globl el3_panic
#if CRASH_REPORTING
#define REG_SIZE 0x8
/* ------------------------------------------------------
* The below section deals with dumping the system state
* when an unhandled exception is taken in EL3.
@ -46,267 +48,304 @@
* be dumped during a unhandled exception is given below.
* ------------------------------------------------------
*/
.section .rodata.dump_reg_name, "aS"
caller_saved_regs: .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16",\
"x17", "x18", ""
.section .rodata.crash_prints, "aS"
print_spacer:
.asciz " =\t\t0x"
callee_saved_regs: .asciz "x19", "x20", "x21", "x22", "x23", "x24",\
"x25", "x26", "x27", "x28", "x29", "x30", ""
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", ""
el3_sys_regs: .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3", "esr_el3",\
"sp_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", "dacr32_el2", "ifsr32_el2", "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", "fpexc32_el2", "sp_el0", ""
non_el3_sys_0_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", ""
panic_msg:
.asciz "PANIC in EL3 at x30 = 0x"
excpt_msg:
.asciz "Unhandled Exception in EL3.\nx30 =\t\t0x"
intr_excpt_msg:
.asciz "Unhandled Interrupt Exception in EL3.\nx30 =\t\t0x"
non_el3_sys_1_regs: .asciz "tpidr_el0", "tpidrro_el0", "dacr32_el2",\
"ifsr32_el2", "par_el1", "far_el1", "afsr0_el1", "afsr1_el1",\
"contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\
"cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "fpexc32_el2",\
"sp_el0", ""
/*
* Helper function to print newline to console.
*/
func print_newline
mov x0, '\n'
b plat_crash_console_putc
/*
* 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
/* update x6 with the updated list pointer */
mov x6, x4
adr x4, print_spacer
bl asm_print_str
ldr x4, [x7], #REG_SIZE
bl asm_print_hex
bl print_newline
b test_size_list
exit_size_print:
mov x30, sp
ret
/*
* 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, #REG_SIZE * 2]
stp x12, x13, [x0, #REG_SIZE * 4]
stp x14, x15, [x0, #REG_SIZE * 6]
b size_controlled_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, #REG_SIZE]
mov x1, sp
str x1, [x0]
.endm
/* -----------------------------------------------------
* Currently we are stack limited. Hence make sure that
* we dont try to dump more than 20 registers using the
* stack.
* 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
#define REG_SIZE 0x8
/* The caller saved registers are X0 to X18 */
#define CALLER_SAVED_REG_SIZE (20 * REG_SIZE)
/* The caller saved registers are X19 to X30 */
#define CALLEE_SAVED_REG_SIZE (12 * REG_SIZE)
/* The EL3 sys regs*/
#define EL3_SYS_REG_SIZE (12 * REG_SIZE)
/* The non EL3 sys regs set-0 */
#define NON_EL3_SYS_0_REG_SIZE (18 * REG_SIZE)
/* The non EL3 sys regs set-1 */
#define NON_EL3_SYS_1_REG_SIZE (18 * REG_SIZE)
/* -----------------------------------------------------
* 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
.macro print_caller_saved_regs
sub sp, sp, #CALLER_SAVED_REG_SIZE
stp x0, x1, [sp]
stp x2, x3, [sp, #(REG_SIZE * 2)]
stp x4, x5, [sp, #(REG_SIZE * 4)]
stp x6, x7, [sp, #(REG_SIZE * 6)]
stp x8, x9, [sp, #(REG_SIZE * 8)]
stp x10, x11, [sp, #(REG_SIZE * 10)]
stp x12, x13, [sp, #(REG_SIZE * 12)]
stp x14, x15, [sp, #(REG_SIZE * 14)]
stp x16, x17, [sp, #(REG_SIZE * 16)]
stp x18, xzr, [sp, #(REG_SIZE * 18)]
adr x0, caller_saved_regs
mov x1, sp
bl print_string_value
add sp, sp, #CALLER_SAVED_REG_SIZE
.endm
/* -----------------------------------------------------
* 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, #1
prepare_crash_buf_save_x0_x1
adr x0, panic_msg
mov sp, x0
/* This call will not return */
b do_crash_reporting
.macro print_callee_saved_regs
sub sp, sp, CALLEE_SAVED_REG_SIZE
stp x19, x20, [sp]
stp x21, x22, [sp, #(REG_SIZE * 2)]
stp x23, x24, [sp, #(REG_SIZE * 4)]
stp x25, x26, [sp, #(REG_SIZE * 6)]
stp x27, x28, [sp, #(REG_SIZE * 8)]
stp x29, x30, [sp, #(REG_SIZE * 10)]
adr x0, callee_saved_regs
mov x1, sp
bl print_string_value
add sp, sp, #CALLEE_SAVED_REG_SIZE
.endm
/* ------------------------------------------------------------
* 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.
* ------------------------------------------------------------
*/
func 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, #REG_SIZE * 2]
stp x4, x5, [x0, #REG_SIZE * 4]
stp x6, x30, [x0, #REG_SIZE * 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
/* load the crash buf address */
mrs x0, tpidr_el3
/* report x30 first from the crash buf */
ldr x4, [x0, #REG_SIZE * 7]
bl asm_print_hex
bl print_newline
/* Load the crash buf address */
mrs x0, tpidr_el3
/* Now mov x7 into crash buf */
str x7, [x0, #REG_SIZE * 7]
.macro print_el3_sys_regs
sub sp, sp, #EL3_SYS_REG_SIZE
mrs x9, scr_el3
mrs x10, sctlr_el3
mrs x11, cptr_el3
mrs x12, tcr_el3
mrs x13, daif
mrs x14, mair_el3
mrs x15, spsr_el3 /*save the elr and spsr regs seperately*/
mrs x16, elr_el3
mrs x17, ttbr0_el3
mrs x8, esr_el3
mrs x7, far_el3
/* 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, #REG_SIZE * 2]
stp x20, x21, [x0, #REG_SIZE * 4]
stp x22, x23, [x0, #REG_SIZE * 6]
bl size_controlled_print
/* Load the crash buf address */
mrs x0, tpidr_el3
stp x24, x25, [x0]
stp x26, x27, [x0, #REG_SIZE * 2]
stp x28, x29, [x0, #REG_SIZE * 4]
bl size_controlled_print
stp x9, x10, [sp]
stp x11, x12, [sp, #(REG_SIZE * 2)]
stp x13, x14, [sp, #(REG_SIZE * 4)]
stp x15, x16, [sp, #(REG_SIZE * 6)]
stp x17, x8, [sp, #(REG_SIZE * 8)]
stp x0, x7, [sp, #(REG_SIZE * 10)] /* sp_el3 is in x0 */
adr x0, el3_sys_regs
mov x1, sp
bl print_string_value
add sp, sp, #EL3_SYS_REG_SIZE
.endm
.macro print_non_el3_sys_0_regs
sub sp, sp, #NON_EL3_SYS_0_REG_SIZE
mrs x9, spsr_el1
mrs x10, elr_el1
mrs x11, spsr_abt
mrs x12, spsr_und
mrs x13, spsr_irq
mrs x14, spsr_fiq
mrs x15, sctlr_el1
mrs x16, actlr_el1
mrs x17, cpacr_el1
mrs x8, csselr_el1
stp x9, x10, [sp]
stp x11, x12, [sp, #(REG_SIZE * 2)]
stp x13, x14, [sp, #(REG_SIZE * 4)]
stp x15, x16, [sp, #(REG_SIZE * 6)]
stp x17, x8, [sp, #(REG_SIZE * 8)]
/* Print the el3 sys registers */
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
mrs x16, tcr_el1
mrs x17, tpidr_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, dacr32_el2
mrs x13, ifsr32_el2
mrs x14, par_el1
mrs x15, mpidr_el1
bl str_in_crash_buf_print
mrs x8, afsr0_el1
mrs x9, afsr1_el1
mrs x10, contextidr_el1
mrs x11, vbar_el1
mrs x12, cntp_ctl_el0
mrs x13, cntp_cval_el0
mrs x14, cntv_ctl_el0
mrs x15, cntv_cval_el0
bl str_in_crash_buf_print
mrs x8, cntkctl_el1
mrs x9, fpexc32_el2
mrs x10, sp_el0
bl str_in_crash_buf_print
stp x10, x11, [sp, #(REG_SIZE * 10)]
stp x12, x13, [sp, #(REG_SIZE * 12)]
stp x14, x15, [sp, #(REG_SIZE * 14)]
stp x16, x17, [sp, #(REG_SIZE * 16)]
/* Print the gic registers */
plat_print_gic_regs
adr x0, non_el3_sys_0_regs
mov x1, sp
bl print_string_value
add sp, sp, #NON_EL3_SYS_0_REG_SIZE
.endm
.macro print_non_el3_sys_1_regs
sub sp, sp, #NON_EL3_SYS_1_REG_SIZE
mrs x9, tpidr_el0
mrs x10, tpidrro_el0
mrs x11, dacr32_el2
mrs x12, ifsr32_el2
mrs x13, par_el1
mrs x14, far_el1
mrs x15, afsr0_el1
mrs x16, afsr1_el1
mrs x17, contextidr_el1
mrs x8, vbar_el1
stp x9, x10, [sp]
stp x11, x12, [sp, #(REG_SIZE * 2)]
stp x13, x14, [sp, #(REG_SIZE * 4)]
stp x15, x16, [sp, #(REG_SIZE * 6)]
stp x17, x8, [sp, #(REG_SIZE * 8)]
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, fpexc32_el2
mrs x8, sp_el0
stp x10, x11, [sp, #(REG_SIZE *10)]
stp x12, x13, [sp, #(REG_SIZE * 12)]
stp x14, x15, [sp, #(REG_SIZE * 14)]
stp x8, xzr, [sp, #(REG_SIZE * 16)]
adr x0, non_el3_sys_1_regs
mov x1, sp
bl print_string_value
add sp, sp, #NON_EL3_SYS_1_REG_SIZE
.endm
.macro init_crash_stack
msr cntfrq_el0, x0 /* we can corrupt this reg to free up x0 */
mrs x0, tpidr_el3
/* Check if tpidr is initialized */
cbz x0, infinite_loop
ldr x0, [x0, #CPU_DATA_CRASH_STACK_OFFSET]
/* store the x30 and sp to stack */
str x30, [x0, #-(REG_SIZE)]!
mov x30, sp
str x30, [x0, #-(REG_SIZE)]!
mov sp, x0
mrs x0, cntfrq_el0
.endm
/* ---------------------------------------------------
* The below function initializes the crash dump stack ,
* and prints the system state. This function
* will not return.
* ---------------------------------------------------
*/
func dump_state_and_die
init_crash_stack
print_caller_saved_regs
b print_state
func dump_intr_state_and_die
init_crash_stack
print_caller_saved_regs
plat_print_gic_regs /* fall through to print_state */
print_state:
/* copy the original x30 from stack */
ldr x30, [sp, #REG_SIZE]
print_callee_saved_regs
/* copy the original SP_EL3 from stack to x0 and rewind stack */
ldr x0, [sp], #(REG_SIZE * 2)
print_el3_sys_regs
print_non_el3_sys_0_regs
print_non_el3_sys_1_regs
#else /* CRASH_REPORING */
func dump_state_and_die
dump_intr_state_and_die:
/* Done reporting */
b crash_panic
#else /* CRASH_REPORTING */
func report_unhandled_exception
report_unhandled_interrupt:
b crash_panic
#endif /* CRASH_REPORING */
infinite_loop:
b infinite_loop
#define PCPU_CRASH_STACK_SIZE 0x140
/* -----------------------------------------------------
* Per-cpu crash stacks in normal memory.
* -----------------------------------------------------
*/
declare_stack pcpu_crash_stack, tzfw_normal_stacks, \
PCPU_CRASH_STACK_SIZE, PLATFORM_CORE_COUNT
/* -----------------------------------------------------
* Provides each CPU with a small stacks for reporting
* unhandled exceptions, and stores the stack address
* in cpu_data
*
* This can be called without a runtime stack
* clobbers: x0 - x4
* -----------------------------------------------------
*/
func init_crash_reporting
mov x4, x30
mov x2, #0
adr x3, pcpu_crash_stack
init_crash_loop:
mov x0, x2
bl _cpu_data_by_index
add x3, x3, #PCPU_CRASH_STACK_SIZE
str x3, [x0, #CPU_DATA_CRASH_STACK_OFFSET]
add x2, x2, #1
cmp x2, #PLATFORM_CORE_COUNT
b.lo init_crash_loop
ret x4
func crash_panic
b crash_panic

View File

@ -60,7 +60,7 @@
* -----------------------------------------------------
*/
bl dump_state_and_die
bl report_unhandled_exception
.endm
@ -142,7 +142,7 @@ interrupt_exit_\label:
* where the interrupt was generated.
*/
interrupt_error_\label:
bl dump_intr_state_and_die
bl report_unhandled_interrupt
.endm
@ -158,7 +158,6 @@ interrupt_error_\label:
.endm
.section .vectors, "ax"; .align 11
.align 7
runtime_exceptions:
/* -----------------------------------------------------
@ -170,7 +169,7 @@ sync_exception_sp_el0:
* We don't expect any synchronous exceptions from EL3
* -----------------------------------------------------
*/
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size sync_exception_sp_el0
.align 7
@ -180,17 +179,17 @@ sync_exception_sp_el0:
* -----------------------------------------------------
*/
irq_sp_el0:
bl dump_intr_state_and_die
bl report_unhandled_interrupt
check_vector_size irq_sp_el0
.align 7
fiq_sp_el0:
bl dump_intr_state_and_die
bl report_unhandled_interrupt
check_vector_size fiq_sp_el0
.align 7
serror_sp_el0:
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size serror_sp_el0
/* -----------------------------------------------------
@ -206,22 +205,22 @@ sync_exception_sp_elx:
* There is a high probability that SP_EL3 is corrupted.
* -----------------------------------------------------
*/
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size sync_exception_sp_elx
.align 7
irq_sp_elx:
bl dump_intr_state_and_die
bl report_unhandled_interrupt
check_vector_size irq_sp_elx
.align 7
fiq_sp_elx:
bl dump_intr_state_and_die
bl report_unhandled_interrupt
check_vector_size fiq_sp_elx
.align 7
serror_sp_elx:
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size serror_sp_elx
/* -----------------------------------------------------
@ -258,7 +257,7 @@ fiq_aarch64:
.align 7
serror_aarch64:
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size serror_aarch64
/* -----------------------------------------------------
@ -295,7 +294,7 @@ fiq_aarch32:
.align 7
serror_aarch32:
bl dump_state_and_die
bl report_unhandled_exception
check_vector_size serror_aarch32
.align 7
@ -473,7 +472,7 @@ smc_prohibited:
rt_svc_fw_critical_error:
msr spsel, #1 /* Switch to SP_ELx */
bl dump_state_and_die
bl report_unhandled_exception
/* -----------------------------------------------------
* The following functions are used to saved and restore

View File

@ -32,13 +32,5 @@
#include <cpu_data.h>
#include <platform_def.h>
/* verify assembler offsets match data structures */
CASSERT(CPU_DATA_CRASH_STACK_OFFSET == __builtin_offsetof
(cpu_data_t, crash_stack),
assert_cpu_data_crash_stack_offset_mismatch);
CASSERT((1 << CPU_DATA_LOG2SIZE) == sizeof(cpu_data_t),
assert_cpu_data_log2size_mismatch);
/* The per_cpu_ptr_cache_t space allocation */
cpu_data_t percpu_data[PLATFORM_CORE_COUNT];

View File

@ -139,3 +139,50 @@ func asm_print_hex
cbnz x5, 1b
ret x3
/***********************************************************
* The common implementation of do_panic for all BL stages
***********************************************************/
.section .rodata.panic_str, "aS"
panic_msg: .asciz "PANIC at PC : 0x"
/* ---------------------------------------------------------------------------
* do_panic assumes that it is invoked from a C Runtime Environment ie a
* valid stack exists. This call will not return.
* Clobber list : if CRASH_REPORTING is not enabled then x30, x0 - x6
* ---------------------------------------------------------------------------
*/
/* This is for the non el3 BL stages to compile through */
.weak el3_panic
func do_panic
#if CRASH_REPORTING
str x0, [sp, #-0x10]!
mrs x0, currentel
ubfx x0, x0, #2, #2
cmp x0, #0x3
ldr x0, [sp], #0x10
b.eq el3_panic
#endif
panic_common:
/*
* el3_panic will be redefined by the BL31
* crash reporting mechanism (if enabled)
*/
el3_panic:
mov x6, x30
bl plat_crash_console_init
/* Check if the console is initialized */
cbz x0, _panic_loop
/* The console is initialized */
adr x4, panic_msg
bl asm_print_str
mov x4, x6
/* The panic location is lr -4 */
sub x4, x4, #4
bl asm_print_hex
_panic_loop:
b _panic_loop

View File

@ -1,96 +0,0 @@
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <console.h>
#include <debug.h>
#include <stdarg.h>
#include <stdio.h>
/******************************************************************
* This function is invoked from assembler error handling routines and
* prints out the string and the value in 64 bit hex format. These
* are passed to the function as input parameters.
********************************************************************/
void print_string_value(char *s, unsigned long *mem)
{
unsigned char i, temp;
unsigned long val;
while (*s) {
i = 16;
while (*s)
console_putc(*s++);
s++;
console_putc('\t');
console_putc(':');
console_putc('0');
console_putc('x');
val = *mem++;
while (i--) {
temp = (val >> (i << 2)) & 0xf;
if (temp < 0xa)
console_putc('0' + temp);
else
console_putc('A' + (temp - 0xa));
}
console_putc('\n');
}
}
/***********************************************************
* The common implementation of do_panic for all BL stages
***********************************************************/
#if DEBUG
void __dead2 do_panic(const char *file, int line)
{
tf_printf("PANIC in file: %s line: %d\n", file, line);
while (1)
;
}
#else
void __dead2 do_panic(void)
{
unsigned long pc_reg;
__asm__ volatile("mov %0, x30\n"
: "=r" (pc_reg) : );
/* x30 reports the next eligible instruction whereas we want the
* place where panic() is invoked. Hence decrement by 4.
*/
tf_printf("PANIC in PC location 0x%016X\n", pc_reg - 0x4);
while (1)
;
}
#endif

View File

@ -32,9 +32,14 @@
#define __CPU_DATA_H__
/* Offsets for the cpu_data structure */
#define CPU_DATA_CRASH_STACK_OFFSET 0x10
#define CPU_DATA_CRASH_BUF_OFFSET 0x10
#if CRASH_REPORTING
#define CPU_DATA_LOG2SIZE 7
#else
#define CPU_DATA_LOG2SIZE 6
#endif
/* need enough space in crash buffer to save 8 registers */
#define CPU_DATA_CRASH_BUF_SIZE 64
#ifndef __ASSEMBLY__
#include <arch_helpers.h>
@ -61,9 +66,21 @@
typedef struct cpu_data {
void *cpu_context[2];
uint64_t crash_stack;
#if CRASH_REPORTING
uint64_t crash_buf[CPU_DATA_CRASH_BUF_SIZE >> 3];
#endif
} __aligned(CACHE_WRITEBACK_GRANULE) cpu_data_t;
#if CRASH_REPORTING
/* verify assembler offsets match data structures */
CASSERT(CPU_DATA_CRASH_BUF_OFFSET == __builtin_offsetof
(cpu_data_t, crash_buf),
assert_cpu_data_crash_stack_offset_mismatch);
#endif
CASSERT((1 << CPU_DATA_LOG2SIZE) == sizeof(cpu_data_t),
assert_cpu_data_log2size_mismatch);
struct cpu_data *_cpu_data_by_index(uint32_t cpu_index);
struct cpu_data *_cpu_data_by_mpidr(uint64_t mpidr);

View File

@ -52,22 +52,9 @@
#define ERROR(...) tf_printf("ERROR: " __VA_ARGS__)
/* For the moment this Panic function is very basic, Report an error and
* spin. This can be expanded in the future to provide more information.
*/
#if DEBUG
void __dead2 do_panic(const char *file, int line);
#define panic() do_panic(__FILE__, __LINE__)
#else
void __dead2 do_panic(void);
#define panic() do_panic()
#endif
void print_string_value(char *s, unsigned long *mem);
void tf_printf(const char *fmt, ...);
#endif /* __DEBUG_H__ */

View File

@ -32,26 +32,50 @@
#include <plat_config.h>
.section .rodata.gic_reg_name, "aS"
gic_regs: .asciz "gic_iar", "gic_ctlr", ""
gic_regs:
.asciz "gic_hppir", "gic_ahppir", "gic_ctlr", ""
gicd_pend_reg:
.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
newline:
.asciz "\n"
spacer:
.asciz ":\t\t0x"
/* Currently we have only 2 GIC registers to report */
#define GIC_REG_SIZE (2 * 8)
/* ---------------------------------------------
* The below macro prints out relevant GIC
* registers whenever an unhandled exception is
* taken in BL31.
* Clobbers: x0 - x10, x16, sp
* ---------------------------------------------
*/
.macro plat_print_gic_regs
adr x0, plat_config;
ldr w0, [x0, #CONFIG_GICC_BASE_OFFSET]
/* gic base address is now in x0 */
ldr w1, [x0, #GICC_IAR]
ldr w2, [x0, #GICC_CTLR]
sub sp, sp, #GIC_REG_SIZE
stp x1, x2, [sp] /* we store the gic registers as 64 bit */
adr x0, gic_regs
mov x1, sp
bl print_string_value
add sp, sp, #GIC_REG_SIZE
adr x0, plat_config
ldr w16, [x0, #CONFIG_GICC_BASE_OFFSET]
cbz x16, 1f
/* gic base address is now in x16 */
adr x6, gic_regs /* Load the gic reg list to x6 */
/* Load the gic regs to gp regs used by str_in_crash_buf_print */
ldr w8, [x16, #GICC_HPPIR]
ldr w9, [x16, #GICC_AHPPIR]
ldr w10, [x16, #GICC_CTLR]
/* Store to the crash buf and print to cosole */
bl str_in_crash_buf_print
/* Print the GICD_ISPENDR regs */
add x7, x16, #GICD_ISPENDR
adr x4, gicd_pend_reg
bl asm_print_str
2:
sub x4, x7, x16
cmp x4, #0x280
b.eq 1f
bl asm_print_hex
adr x4, spacer
bl asm_print_str
ldr x4, [x7], #8
bl asm_print_hex
adr x4, newline
bl asm_print_str
b 2b
1:
.endm