Commit 6397bf6a authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #172 from soby-mathew/sm/asm_assert

Introduce asm assert and optimize crash reporting
parents 9fd41277 8c106902
...@@ -60,7 +60,9 @@ CTX_INCLUDE_FPREGS := 0 ...@@ -60,7 +60,9 @@ CTX_INCLUDE_FPREGS := 0
# Determine the version of ARM GIC architecture to use for interrupt management # Determine the version of ARM GIC architecture to use for interrupt management
# in EL3. The platform port can change this value if needed. # in EL3. The platform port can change this value if needed.
ARM_GIC_ARCH := 2 ARM_GIC_ARCH := 2
# Flag used to indicate if ASM_ASSERTION should be enabled for the build.
# This defaults to being present in DEBUG builds only.
ASM_ASSERTION := ${DEBUG}
# Checkpatch ignores # Checkpatch ignores
CHECK_IGNORE = --ignore COMPLEX_MACRO CHECK_IGNORE = --ignore COMPLEX_MACRO
...@@ -90,8 +92,8 @@ endif ...@@ -90,8 +92,8 @@ endif
VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING} VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING}
BL_COMMON_SOURCES := common/bl_common.c \ BL_COMMON_SOURCES := common/bl_common.c \
common/debug.c \
common/tf_printf.c \ common/tf_printf.c \
common/aarch64/debug.S \
lib/aarch64/cache_helpers.S \ lib/aarch64/cache_helpers.S \
lib/aarch64/misc_helpers.S \ lib/aarch64/misc_helpers.S \
lib/aarch64/xlat_helpers.c \ lib/aarch64/xlat_helpers.c \
...@@ -207,6 +209,9 @@ $(eval $(call add_define,CTX_INCLUDE_FPREGS)) ...@@ -207,6 +209,9 @@ $(eval $(call add_define,CTX_INCLUDE_FPREGS))
# Process ARM_GIC_ARCH flag # Process ARM_GIC_ARCH flag
$(eval $(call add_define,ARM_GIC_ARCH)) $(eval $(call add_define,ARM_GIC_ARCH))
# Process ASM_ASSERTION flag
$(eval $(call assert_boolean,ASM_ASSERTION))
$(eval $(call add_define,ASM_ASSERTION))
ASFLAGS += -nostdinc -ffreestanding -Wa,--fatal-warnings \ ASFLAGS += -nostdinc -ffreestanding -Wa,--fatal-warnings \
-Werror -Wmissing-include-dirs \ -Werror -Wmissing-include-dirs \
......
...@@ -82,13 +82,22 @@ func bl31_entrypoint ...@@ -82,13 +82,22 @@ func bl31_entrypoint
isb isb
/* --------------------------------------------- /* ---------------------------------------------
* Set the exception vector and zero tpidr_el3 * Initialise cpu_data early to enable crash
* until the crash reporting is set up * 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 adr x1, runtime_exceptions
msr vbar_el3, x1 msr vbar_el3, x1
msr tpidr_el3, xzr
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* The initial state of the Architectural feature trap register * The initial state of the Architectural feature trap register
...@@ -146,15 +155,6 @@ func bl31_entrypoint ...@@ -146,15 +155,6 @@ func bl31_entrypoint
ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__ ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__
bl zeromem16 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. * Use SP_EL0 for the C runtime stack.
* --------------------------------------------- * ---------------------------------------------
......
...@@ -34,11 +34,13 @@ ...@@ -34,11 +34,13 @@
#include <plat_macros.S> #include <plat_macros.S>
#include <platform_def.h> #include <platform_def.h>
.globl dump_state_and_die .globl report_unhandled_exception
.globl dump_intr_state_and_die .globl report_unhandled_interrupt
.globl init_crash_reporting .globl el3_panic
#if CRASH_REPORTING #if CRASH_REPORTING
#define REG_SIZE 0x8
/* ------------------------------------------------------ /* ------------------------------------------------------
* The below section deals with dumping the system state * The below section deals with dumping the system state
* when an unhandled exception is taken in EL3. * when an unhandled exception is taken in EL3.
...@@ -46,267 +48,326 @@ ...@@ -46,267 +48,326 @@
* be dumped during a unhandled exception is given below. * be dumped during a unhandled exception is given below.
* ------------------------------------------------------ * ------------------------------------------------------
*/ */
.section .rodata.dump_reg_name, "aS" .section .rodata.crash_prints, "aS"
caller_saved_regs: .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\ print_spacer:
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16",\ .asciz " =\t\t0x"
"x17", "x18", ""
cpu_ectlr_reg:
callee_saved_regs: .asciz "x19", "x20", "x21", "x22", "x23", "x24",\ .asciz "cpuectlr_el1 =\t\t0x"
"x25", "x26", "x27", "x28", "x29", "x30", ""
gp_regs:
el3_sys_regs: .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\ .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3", "esr_el3",\ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
"sp_el3", "far_el3", "" "x16", "x17", "x18", "x19", "x20", "x21", "x22",\
"x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
non_el3_sys_0_regs: .asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\ 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",\ "spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\
"csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\ "csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\
"mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "" "mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\
"tpidrro_el0", "dacr32_el2", "ifsr32_el2", "par_el1",\
non_el3_sys_1_regs: .asciz "tpidr_el0", "tpidrro_el0", "dacr32_el2",\ "mpidr_el1", "afsr0_el1", "afsr1_el1", "contextidr_el1",\
"ifsr32_el2", "par_el1", "far_el1", "afsr0_el1", "afsr1_el1",\ "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0", "cntv_ctl_el0",\
"contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\ "cntv_cval_el0", "cntkctl_el1", "fpexc32_el2", "sp_el0", ""
"cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "fpexc32_el2",\
"sp_el0", "" panic_msg:
.asciz "PANIC in EL3 at x30 = 0x"
/* ----------------------------------------------------- excpt_msg:
* Currently we are stack limited. Hence make sure that .asciz "Unhandled Exception in EL3.\nx30 =\t\t0x"
* we dont try to dump more than 20 registers using the intr_excpt_msg:
* stack. .asciz "Unhandled Interrupt Exception in EL3.\nx30 =\t\t0x"
* -----------------------------------------------------
/*
* 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
#define REG_SIZE 0x8 /* ------------------------------------------------------
* This macro calculates the offset to crash buf from
/* The caller saved registers are X0 to X18 */ * cpu_data and stores it in tpidr_el3. It also saves x0
#define CALLER_SAVED_REG_SIZE (20 * REG_SIZE) * and x1 in the crash buf by using sp as a temporary
/* The caller saved registers are X19 to X30 */ * register.
#define CALLEE_SAVED_REG_SIZE (12 * REG_SIZE) * ------------------------------------------------------
/* The EL3 sys regs*/ */
#define EL3_SYS_REG_SIZE (12 * REG_SIZE) .macro prepare_crash_buf_save_x0_x1
/* The non EL3 sys regs set-0 */ /* we can corrupt this reg to free up x0 */
#define NON_EL3_SYS_0_REG_SIZE (18 * REG_SIZE) mov sp, x0
/* The non EL3 sys regs set-1 */ /* tpidr_el3 contains the address to cpu_data structure */
#define NON_EL3_SYS_1_REG_SIZE (18 * REG_SIZE) mrs x0, tpidr_el3
/* Calculate the Crash buffer offset in cpu_data */
.macro print_caller_saved_regs add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
sub sp, sp, #CALLER_SAVED_REG_SIZE /* Store crash buffer address in tpidr_el3 */
stp x0, x1, [sp] msr tpidr_el3, x0
stp x2, x3, [sp, #(REG_SIZE * 2)] str x1, [x0, #REG_SIZE]
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
.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 mov x1, sp
bl print_string_value str x1, [x0]
add sp, sp, #CALLEE_SAVED_REG_SIZE
.endm .endm
.macro print_el3_sys_regs /* -----------------------------------------------------
sub sp, sp, #EL3_SYS_REG_SIZE * This function allows to report a crash (if crash
mrs x9, scr_el3 * reporting is enabled) when an unhandled exception
mrs x10, sctlr_el3 * occurs. It prints the CPU state via the crash console
mrs x11, cptr_el3 * making use of the crash buf. This function will
mrs x12, tcr_el3 * not return.
mrs x13, daif * -----------------------------------------------------
mrs x14, mair_el3 */
mrs x15, spsr_el3 /*save the elr and spsr regs seperately*/ func report_unhandled_exception
mrs x16, elr_el3 prepare_crash_buf_save_x0_x1
mrs x17, ttbr0_el3 adr x0, excpt_msg
mrs x8, esr_el3 mov sp, x0
mrs x7, far_el3 /* This call will not return */
b do_crash_reporting
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)] * This function allows to report a crash (if crash
stp x13, x14, [sp, #(REG_SIZE * 4)] * reporting is enabled) when an unhandled interrupt
stp x15, x16, [sp, #(REG_SIZE * 6)] * occurs. It prints the CPU state via the crash console
stp x17, x8, [sp, #(REG_SIZE * 8)] * 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
/* -----------------------------------------------------
* 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
/* ------------------------------------------------------------
* 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]
/* 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
/* 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 x10, sp_el1
mrs x11, esr_el1 mrs x11, esr_el1
mrs x12, ttbr0_el1 mrs x12, ttbr0_el1
mrs x13, ttbr1_el1 mrs x13, ttbr1_el1
mrs x14, mair_el1 mrs x14, mair_el1
mrs x15, amair_el1 mrs x15, amair_el1
mrs x16, tcr_el1 bl str_in_crash_buf_print
mrs x17, tpidr_el1 mrs x8, tcr_el1
mrs x9, tpidr_el1
stp x10, x11, [sp, #(REG_SIZE * 10)] mrs x10, tpidr_el0
stp x12, x13, [sp, #(REG_SIZE * 12)] mrs x11, tpidrro_el0
stp x14, x15, [sp, #(REG_SIZE * 14)] mrs x12, dacr32_el2
stp x16, x17, [sp, #(REG_SIZE * 16)] mrs x13, ifsr32_el2
mrs x14, par_el1
adr x0, non_el3_sys_0_regs mrs x15, mpidr_el1
mov x1, sp bl str_in_crash_buf_print
bl print_string_value mrs x8, afsr0_el1
add sp, sp, #NON_EL3_SYS_0_REG_SIZE mrs x9, afsr1_el1
.endm mrs x10, contextidr_el1
mrs x11, vbar_el1
.macro print_non_el3_sys_1_regs mrs x12, cntp_ctl_el0
sub sp, sp, #NON_EL3_SYS_1_REG_SIZE mrs x13, cntp_cval_el0
mrs x14, cntv_ctl_el0
mrs x9, tpidr_el0 mrs x15, cntv_cval_el0
mrs x10, tpidrro_el0 bl str_in_crash_buf_print
mrs x11, dacr32_el2 mrs x8, cntkctl_el1
mrs x12, ifsr32_el2 mrs x9, fpexc32_el2
mrs x13, par_el1 mrs x10, sp_el0
mrs x14, far_el1 bl str_in_crash_buf_print
mrs x15, afsr0_el1
mrs x16, afsr1_el1 /* Print the CPUECTLR_EL1 reg */
mrs x17, contextidr_el1 mrs x0, midr_el1
mrs x8, vbar_el1 lsr x0, x0, #MIDR_PN_SHIFT
and x0, x0, #MIDR_PN_MASK
stp x9, x10, [sp] cmp x0, #MIDR_PN_A57
stp x11, x12, [sp, #(REG_SIZE * 2)] b.eq 1f
stp x13, x14, [sp, #(REG_SIZE * 4)] cmp x0, #MIDR_PN_A53
stp x15, x16, [sp, #(REG_SIZE * 6)] b.ne 2f
stp x17, x8, [sp, #(REG_SIZE * 8)] 1:
adr x4, cpu_ectlr_reg
mrs x10, cntp_ctl_el0 bl asm_print_str
mrs x11, cntp_cval_el0 mrs x4, CPUECTLR_EL1
mrs x12, cntv_ctl_el0 bl asm_print_hex
mrs x13, cntv_cval_el0 bl print_newline
mrs x14, cntkctl_el1 2:
mrs x15, fpexc32_el2
mrs x8, sp_el0 /* Print the gic registers */
plat_print_gic_regs
stp x10, x11, [sp, #(REG_SIZE *10)]
stp x12, x13, [sp, #(REG_SIZE * 12)] /* Print the interconnect registers */
stp x14, x15, [sp, #(REG_SIZE * 14)] plat_print_interconnect_regs
stp x8, xzr, [sp, #(REG_SIZE * 16)]
/* Done reporting */
adr x0, non_el3_sys_1_regs b crash_panic
mov x1, sp
bl print_string_value #else /* CRASH_REPORTING */
add sp, sp, #NON_EL3_SYS_1_REG_SIZE func report_unhandled_exception
.endm report_unhandled_interrupt:
b crash_panic
.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:
#endif /* CRASH_REPORING */ #endif /* CRASH_REPORING */
infinite_loop:
b infinite_loop
func crash_panic
#define PCPU_CRASH_STACK_SIZE 0x140 b crash_panic
/* -----------------------------------------------------
* 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
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
* ----------------------------------------------------- * -----------------------------------------------------
*/ */
bl dump_state_and_die bl report_unhandled_exception
.endm .endm
...@@ -142,7 +142,7 @@ interrupt_exit_\label: ...@@ -142,7 +142,7 @@ interrupt_exit_\label:
* where the interrupt was generated. * where the interrupt was generated.
*/ */
interrupt_error_\label: interrupt_error_\label:
bl dump_intr_state_and_die bl report_unhandled_interrupt
.endm .endm
...@@ -158,7 +158,6 @@ interrupt_error_\label: ...@@ -158,7 +158,6 @@ interrupt_error_\label:
.endm .endm
.section .vectors, "ax"; .align 11 .section .vectors, "ax"; .align 11
.align 7 .align 7
runtime_exceptions: runtime_exceptions:
/* ----------------------------------------------------- /* -----------------------------------------------------
...@@ -170,7 +169,7 @@ sync_exception_sp_el0: ...@@ -170,7 +169,7 @@ sync_exception_sp_el0:
* We don't expect any synchronous exceptions from EL3 * 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 check_vector_size sync_exception_sp_el0
.align 7 .align 7
...@@ -180,17 +179,17 @@ sync_exception_sp_el0: ...@@ -180,17 +179,17 @@ sync_exception_sp_el0:
* ----------------------------------------------------- * -----------------------------------------------------
*/ */
irq_sp_el0: irq_sp_el0:
bl dump_intr_state_and_die bl report_unhandled_interrupt
check_vector_size irq_sp_el0 check_vector_size irq_sp_el0
.align 7 .align 7
fiq_sp_el0: fiq_sp_el0:
bl dump_intr_state_and_die bl report_unhandled_interrupt
check_vector_size fiq_sp_el0 check_vector_size fiq_sp_el0
.align 7 .align 7
serror_sp_el0: serror_sp_el0:
bl dump_state_and_die bl report_unhandled_exception
check_vector_size serror_sp_el0 check_vector_size serror_sp_el0
/* ----------------------------------------------------- /* -----------------------------------------------------
...@@ -206,22 +205,22 @@ sync_exception_sp_elx: ...@@ -206,22 +205,22 @@ sync_exception_sp_elx:
* There is a high probability that SP_EL3 is corrupted. * 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 check_vector_size sync_exception_sp_elx
.align 7 .align 7
irq_sp_elx: irq_sp_elx:
bl dump_intr_state_and_die bl report_unhandled_interrupt
check_vector_size irq_sp_elx check_vector_size irq_sp_elx
.align 7 .align 7
fiq_sp_elx: fiq_sp_elx:
bl dump_intr_state_and_die bl report_unhandled_interrupt
check_vector_size fiq_sp_elx check_vector_size fiq_sp_elx
.align 7 .align 7
serror_sp_elx: serror_sp_elx:
bl dump_state_and_die bl report_unhandled_exception
check_vector_size serror_sp_elx check_vector_size serror_sp_elx
/* ----------------------------------------------------- /* -----------------------------------------------------
...@@ -258,7 +257,7 @@ fiq_aarch64: ...@@ -258,7 +257,7 @@ fiq_aarch64:
.align 7 .align 7
serror_aarch64: serror_aarch64:
bl dump_state_and_die bl report_unhandled_exception
check_vector_size serror_aarch64 check_vector_size serror_aarch64
/* ----------------------------------------------------- /* -----------------------------------------------------
...@@ -295,7 +294,7 @@ fiq_aarch32: ...@@ -295,7 +294,7 @@ fiq_aarch32:
.align 7 .align 7
serror_aarch32: serror_aarch32:
bl dump_state_and_die bl report_unhandled_exception
check_vector_size serror_aarch32 check_vector_size serror_aarch32
.align 7 .align 7
...@@ -473,7 +472,7 @@ smc_prohibited: ...@@ -473,7 +472,7 @@ smc_prohibited:
rt_svc_fw_critical_error: rt_svc_fw_critical_error:
msr spsel, #1 /* Switch to SP_ELx */ 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 * The following functions are used to saved and restore
......
...@@ -32,13 +32,5 @@ ...@@ -32,13 +32,5 @@
#include <cpu_data.h> #include <cpu_data.h>
#include <platform_def.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 */ /* The per_cpu_ptr_cache_t space allocation */
cpu_data_t percpu_data[PLATFORM_CORE_COUNT]; cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
/*
* 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 <arch.h>
#include <asm_macros.S>
.globl asm_print_str
.globl asm_print_hex
.globl asm_assert
.globl do_panic
/* Since the max decimal input number is 65536 */
#define MAX_DEC_DIVISOR 10000
/* The offset to add to get ascii for numerals '0 - 9' */
#define ASCII_OFFSET_NUM 0x30
#if ASM_ASSERTION
.section .rodata.assert_str, "aS"
assert_msg1:
.asciz "ASSERT: File "
assert_msg2:
.asciz " Line "
/*
* This macro is intended to be used to print the
* line number in decimal. Used by asm_assert macro.
* The max number expected is 65536.
* In: x4 = the decimal to print.
* Clobber: x30, x0, x1, x2, x5, x6
*/
.macro asm_print_line_dec
mov x6, #10 /* Divide by 10 after every loop iteration */
mov x5, #MAX_DEC_DIVISOR
1:
udiv x0, x4, x5 /* Get the quotient */
msub x4, x0, x5, x4 /* Find the remainder */
add x0, x0, #ASCII_OFFSET_NUM /* Convert to ascii */
bl plat_crash_console_putc
udiv x5, x5, x6 /* Reduce divisor */
cbnz x5, 1b
.endm
/* ---------------------------------------------------------------------------
* Assertion support in assembly.
* The below function helps to support assertions in assembly where we do not
* have a C runtime stack. Arguments to the function are :
* x0 - File name
* x1 - Line no
* Clobber list : x30, x0, x1, x2, x3, x4, x5, x6.
* ---------------------------------------------------------------------------
*/
func asm_assert
mov x5, x0
mov x6, x1
/* Ensure the console is initialized */
bl plat_crash_console_init
/* Check if the console is initialized */
cbz x0, _assert_loop
/* The console is initialized */
adr x4, assert_msg1
bl asm_print_str
mov x4, x5
bl asm_print_str
adr x4, assert_msg2
bl asm_print_str
/* Check if line number higher than max permitted */
tst x6, #~0xffff
b.ne _assert_loop
mov x4, x6
asm_print_line_dec
_assert_loop:
b _assert_loop
#endif
/*
* This function prints a string from address in x4.
* In: x4 = pointer to string.
* Clobber: x30, x0, x1, x2, x3
*/
func asm_print_str
mov x3, x30
1:
ldrb w0, [x4], #0x1
cbz x0, 2f
bl plat_crash_console_putc
b 1b
2:
ret x3
/*
* This function prints a hexadecimal number in x4.
* In: x4 = the hexadecimal to print.
* Clobber: x30, x0, x5, x1, x2, x3
*/
func asm_print_hex
mov x3, x30
mov x5, #64 /* No of bits to convert to ascii */
1:
sub x5, x5, #4
lsrv x0, x4, x5
and x0, x0, #0xf
cmp x0, #0xA
b.lo 2f
/* Add by 0x27 in addition to ASCII_OFFSET_NUM
* to get ascii for characters 'a - f'.
*/
add x0, x0, #0x27
2:
add x0, x0, #ASCII_OFFSET_NUM
bl plat_crash_console_putc
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
/*
* 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
...@@ -15,6 +15,7 @@ Contents ...@@ -15,6 +15,7 @@ Contents
* Boot Loader stage 3-1 (BL3-1) * Boot Loader stage 3-1 (BL3-1)
* PSCI implementation (in BL3-1) * PSCI implementation (in BL3-1)
* Interrupt Management framework (in BL3-1) * Interrupt Management framework (in BL3-1)
* Crash Reporting mechanism (in BL3-1)
4. C Library 4. C Library
5. Storage abstraction layer 5. Storage abstraction layer
...@@ -268,10 +269,18 @@ the following macro defined. In the ARM FVP port, this file is found in ...@@ -268,10 +269,18 @@ the following macro defined. In the ARM FVP port, this file is found in
* **Macro : plat_print_gic_regs** * **Macro : plat_print_gic_regs**
This macro allows the crash reporting routine to print GIC registers This macro allows the crash reporting routine to print GIC registers
in case of an unhandled IRQ or FIQ in BL3-1. This aids in debugging and in case of an unhandled exception in BL3-1. This aids in debugging and
this macro can be defined to be empty in case GIC register reporting is this macro can be defined to be empty in case GIC register reporting is
not desired. not desired.
* **Macro : plat_print_interconnect_regs**
This macro allows the crash reporting routine to print interconnect registers
in case of an unhandled exception in BL3-1. This aids in debugging and
this macro can be defined to be empty in case interconnect register reporting
is not desired. In the ARM FVP port, the CCI snoop control registers are
reported.
### Other mandatory modifications ### Other mandatory modifications
The following mandatory modifications may be implemented in any file The following mandatory modifications may be implemented in any file
...@@ -1265,6 +1274,41 @@ interrupts as Group1 interrupts. It reads the group value corresponding to the ...@@ -1265,6 +1274,41 @@ interrupts as Group1 interrupts. It reads the group value corresponding to the
interrupt id from the relevant _Interrupt Group Register_ (`GICD_IGROUPRn`). It interrupt id from the relevant _Interrupt Group Register_ (`GICD_IGROUPRn`). It
uses the group value to determine the type of interrupt. uses the group value to determine the type of interrupt.
3.5 Crash Reporting mechanism (in BL3-1)
----------------------------------------------
BL3-1 implements a crash reporting mechanism which prints the various registers
of the CPU to enable quick crash analysis and debugging. It requires that a console
is designated as the crash console by the platform which will used to print the
register dump.
The following functions must be implemented by the platform if it wants crash reporting
mechanism in BL3-1. The functions are implemented in assembly so that they can be
invoked without a C Runtime stack.
### Function : plat_crash_console_init
Argument : void
Return : int
This API is used by the crash reporting mechanism to intialize the crash console.
It should only use the general purpose registers x0 to x2 to do the initiaization
and returns 1 on success.
The FVP port designates the PL011_UART0 as the crash console and calls the
console_core_init() to initialize the console.
### Function : plat_crash_console_putc
Argument : int
Return : int
This API is used by the crash reporting mechanism to print a character on the
designated crash console. It should only use general purpose registers x1 and
x2 to do its work. The parameter and the return value are in general purpose
register x0.
The FVP port designates the PL011_UART0 as the crash console and calls the
console_core_putc() to print the character on the console.
4. C Library 4. C Library
------------- -------------
......
...@@ -181,6 +181,11 @@ performed. ...@@ -181,6 +181,11 @@ performed.
BL3-1. This option defaults to the value of `DEBUG` - i.e. by default BL3-1. This option defaults to the value of `DEBUG` - i.e. by default
this is only enabled for a debug build of the firmware. this is only enabled for a debug build of the firmware.
* `ASM_ASSERTION`: This flag determines whether the assertion checks within
assembly source files are enabled or not. This option defaults to the
value of `DEBUG` - i.e. by default this is only enabled for a debug
build of the firmware.
### Creating a Firmware Image Package ### Creating a Firmware Image Package
FIPs are automatically created as part of the build instructions described in FIPs are automatically created as part of the build instructions described in
......
/*
* Copyright (c) 2013-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 <arch.h>
#include <asm_macros.S>
#include <pl011.h>
.globl console_init
.globl console_putc
.globl console_core_init
.globl console_core_putc
.globl console_getc
/*
* The console base is in the data section and not in .bss
* even though it is zero-init. In particular, this allows
* the console functions to start using this variable before
* the runtime memory is initialized for images which do not
* need to copy the .data section from ROM to RAM.
*/
.section .data.console_base ; .align 3
console_base: .quad 0x0
/* -----------------------------------------------
* int console_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. It saves
* the console base to the data section.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* out: return 1 on success.
* Clobber list : x1 - x3
* -----------------------------------------------
*/
func console_init
adrp x3, console_base
str x0, [x3, :lo12:console_base]
b console_core_init
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success
* Clobber list : x1, x2
* -----------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, init_fail
cbz w2, init_fail
/* Program the baudrate */
/* Divisor = (Uart clock * 4) / baudrate */
lsl w1, w1, #2
udiv w2, w1, w2
/* IBRD = Divisor >> 6 */
lsr w1, w2, #6
/* Write the IBRD */
str w1, [x0, #UARTIBRD]
/* FBRD = Divisor & 0x3F */
and w1, w2, #0x3f
/* Write the FBRD */
str w1, [x0, #UARTFBRD]
mov w1, #PL011_LINE_CONTROL
str w1, [x0, #UARTLCR_H]
/* Clear any pending errors */
str wzr, [x0, #UARTECR]
/* Enable tx, rx, and uart overall */
mov w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
str w1, [x0, #UARTCR]
mov w0, #1
init_fail:
ret
/* ---------------------------------------------
* int console_putc(int c)
* Function to output a character over the
* console. It returns the character printed on
* success or -1 on error.
* In : x0 - character to be printed
* Out : return -1 on error else return character.
* Clobber list : x1, x2
* ---------------------------------------------
*/
func console_putc
adrp x2, console_base
ldr x1, [x2, :lo12:console_base]
b console_core_putc
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned int base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
1:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UARTFR]
tbnz w2, #PL011_UARTFR_TXFF_BIT, 1b
mov w2, #0xD
str w2, [x1, #UARTDR]
2:
/* Check if the transmit FIFO is full */
ldr w2, [x1, #UARTFR]
tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b
str w0, [x1, #UARTDR]
ret
putc_error:
mov w0, #-1
ret
/* ---------------------------------------------
* int console_getc(void)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_getc
adrp x0, console_base
ldr x1, [x0, :lo12:console_base]
cbz x1, getc_error
1:
/* Check if the receive FIFO is empty */
ldr w0, [x1, #UARTFR]
tbnz w0, #PL011_UARTFR_RXFE_BIT, 1b
ldr w0, [x1, #UARTDR]
ret
getc_error:
mov w0, #-1
ret
/*
* Copyright (c) 2013-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 <assert.h>
#include <console.h>
#include <pl011.h>
static unsigned long uart_base;
void console_init(unsigned long base_addr)
{
/* TODO: assert() internally calls printf() and will result in
* an infinite loop. This needs to be fixed with some kind of
* exception mechanism or early panic support. This also applies
* to the other assert() calls below.
*/
assert(base_addr);
/* Initialise internal base address variable */
uart_base = base_addr;
/* Baud Rate */
#if defined(PL011_INTEGER) && defined(PL011_FRACTIONAL)
pl011_write_ibrd(uart_base, PL011_INTEGER);
pl011_write_fbrd(uart_base, PL011_FRACTIONAL);
#else
pl011_setbaudrate(uart_base, PL011_BAUDRATE);
#endif
pl011_write_lcr_h(uart_base, PL011_LINE_CONTROL);
/* Clear any pending errors */
pl011_write_ecr(uart_base, 0);
/* Enable tx, rx, and uart overall */
pl011_write_cr(uart_base, PL011_UARTCR_RXE | PL011_UARTCR_TXE |
PL011_UARTCR_UARTEN);
}
#define WAIT_UNTIL_UART_FREE(base) \
while ((pl011_read_fr(base) & PL011_UARTFR_TXFF)) \
continue
int console_putc(int c)
{
/* If the console has not been initialized then return an error
* code. Asserting here would result in recursion and stack
* exhaustion
*/
if (!uart_base)
return -1;
if (c == '\n') {
WAIT_UNTIL_UART_FREE(uart_base);
pl011_write_dr(uart_base, '\r');
}
WAIT_UNTIL_UART_FREE(uart_base);
pl011_write_dr(uart_base, c);
return c;
}
int console_getc(void)
{
assert(uart_base);
while ((pl011_read_fr(uart_base) & PL011_UARTFR_RXFE) != 0)
;
return pl011_read_dr(uart_base);
}
...@@ -32,9 +32,14 @@ ...@@ -32,9 +32,14 @@
#define __CPU_DATA_H__ #define __CPU_DATA_H__
/* Offsets for the cpu_data structure */ /* 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 #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__ #ifndef __ASSEMBLY__
#include <arch_helpers.h> #include <arch_helpers.h>
...@@ -61,9 +66,21 @@ ...@@ -61,9 +66,21 @@
typedef struct cpu_data { typedef struct cpu_data {
void *cpu_context[2]; 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; } __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_index(uint32_t cpu_index);
struct cpu_data *_cpu_data_by_mpidr(uint64_t mpidr); struct cpu_data *_cpu_data_by_mpidr(uint64_t mpidr);
......
...@@ -162,3 +162,36 @@ wait_for_entrypoint: ...@@ -162,3 +162,36 @@ wait_for_entrypoint:
.macro get_up_stack _name, _size .macro get_up_stack _name, _size
ldr x0, =(\_name + \_size) ldr x0, =(\_name + \_size)
.endm .endm
/*
* Helper macro to generate the best mov/movk combinations according
* the value to be moved. The 16 bits from '_shift' are tested and
* if not zero, they are moved into '_reg' without affecting
* other bits.
*/
.macro _mov_imm16 _reg, _val, _shift
.if (\_val >> \_shift) & 0xffff
.if (\_val & (1 << \_shift - 1))
movk \_reg, (\_val >> \_shift) & 0xffff, LSL \_shift
.else
mov \_reg, \_val & (0xffff << \_shift)
.endif
.endif
.endm
/*
* Helper macro to load arbitrary values into 32 or 64-bit registers
* which generates the best mov/movk combinations. Many base addresses
* are 64KB aligned the macro will eliminate updating bits 15:0 in
* that case
*/
.macro mov_imm _reg, _val
.if (\_val) == 0
mov \_reg, #0
.else
_mov_imm16 \_reg, (\_val), 0
_mov_imm16 \_reg, (\_val), 16
_mov_imm16 \_reg, (\_val), 32
_mov_imm16 \_reg, (\_val), 48
.endif
.endm
/* /*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
...@@ -28,14 +28,19 @@ ...@@ -28,14 +28,19 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <assert.h> /*
#include <pl011.h> * Assembler macro to enable asm_assert. Use this macro wherever
* assert is required in assembly.
void pl011_setbaudrate(unsigned long base_addr, unsigned int baudrate) */
{ #define ASM_ASSERT(_cc) \
unsigned int divisor; .ifndef .L_assert_filename ;\
assert(baudrate); .pushsection .rodata.str1.1, "aS" ;\
divisor = (PL011_CLK_IN_HZ * 4) / baudrate; .L_assert_filename: ;\
pl011_write_ibrd(base_addr, divisor >> 6); .string __FILE__ ;\
pl011_write_fbrd(base_addr, divisor & 0x3F); .popsection ;\
} .endif ;\
b._cc 1f ;\
adr x0, .L_assert_filename ;\
mov x1, __LINE__ ;\
b asm_assert ;\
1:
...@@ -52,22 +52,9 @@ ...@@ -52,22 +52,9 @@
#define ERROR(...) tf_printf("ERROR: " __VA_ARGS__) #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); void __dead2 do_panic(void);
#define panic() do_panic() #define panic() do_panic()
#endif
void print_string_value(char *s, unsigned long *mem);
void tf_printf(const char *fmt, ...); void tf_printf(const char *fmt, ...);
#endif /* __DEBUG_H__ */ #endif /* __DEBUG_H__ */
...@@ -65,8 +65,11 @@ ...@@ -65,8 +65,11 @@
/* Status register bit definitions */ /* Status register bit definitions */
#define CHANGE_PENDING_BIT (1 << 0) #define CHANGE_PENDING_BIT (1 << 0)
#ifndef __ASSEMBLY__
/* Function declarations */ /* Function declarations */
void cci_enable_coherency(unsigned long mpidr); void cci_enable_coherency(unsigned long mpidr);
void cci_disable_coherency(unsigned long mpidr); void cci_disable_coherency(unsigned long mpidr);
#endif /* __ASSEMBLY__ */
#endif /* __CCI_400_H__ */ #endif /* __CCI_400_H__ */
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
#ifndef __PL011_H__ #ifndef __PL011_H__
#define __PL011_H__ #define __PL011_H__
#include <mmio.h>
/* PL011 Registers */ /* PL011 Registers */
#define UARTDR 0x000 #define UARTDR 0x000
#define UARTRSR 0x004 #define UARTRSR 0x004
...@@ -68,6 +65,9 @@ ...@@ -68,6 +65,9 @@
#define PL011_UARTFR_DSR (1 << 1) /* Data set ready */ #define PL011_UARTFR_DSR (1 << 1) /* Data set ready */
#define PL011_UARTFR_CTS (1 << 0) /* Clear to send */ #define PL011_UARTFR_CTS (1 << 0) /* Clear to send */
#define PL011_UARTFR_TXFF_BIT 5 /* Transmit FIFO full bit in UARTFR register */
#define PL011_UARTFR_RXFE_BIT 4 /* Receive FIFO empty bit in UARTFR register */
/* Control reg bits */ /* Control reg bits */
#define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */ #define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */
#define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */ #define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */
...@@ -78,14 +78,6 @@ ...@@ -78,14 +78,6 @@
#define PL011_UARTCR_LBE (1 << 7) /* Loopback enable */ #define PL011_UARTCR_LBE (1 << 7) /* Loopback enable */
#define PL011_UARTCR_UARTEN (1 << 0) /* UART Enable */ #define PL011_UARTCR_UARTEN (1 << 0) /* UART Enable */
#if !defined(PL011_BAUDRATE)
#define PL011_BAUDRATE 115200
#endif
#if !defined(PL011_CLK_IN_HZ)
#define PL011_CLK_IN_HZ 24000000
#endif
#if !defined(PL011_LINE_CONTROL) #if !defined(PL011_LINE_CONTROL)
/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */ /* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
#define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8) #define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8)
...@@ -103,58 +95,4 @@ ...@@ -103,58 +95,4 @@
#define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */ #define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */
#define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */ #define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */
/*******************************************************************************
* Pl011 CPU interface accessors for writing registers
******************************************************************************/
static inline void pl011_write_ibrd(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTIBRD, val);
}
static inline void pl011_write_fbrd(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTFBRD, val);
}
static inline void pl011_write_lcr_h(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTLCR_H, val);
}
static inline void pl011_write_ecr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTECR, val);
}
static inline void pl011_write_cr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTCR, val);
}
static inline void pl011_write_dr(unsigned long base, unsigned int val)
{
mmio_write_32(base + UARTDR, val);
}
/*******************************************************************************
* Pl011 CPU interface accessors for reading registers
******************************************************************************/
static inline unsigned int pl011_read_fr(unsigned long base)
{
return mmio_read_32(base + UARTFR);
}
static inline unsigned int pl011_read_dr(unsigned long base)
{
return mmio_read_32(base + UARTDR);
}
/*******************************************************************************
* Function prototypes
******************************************************************************/
void pl011_setbaudrate(unsigned long base_addr, unsigned int baudrate);
#endif /* __PL011_H__ */ #endif /* __PL011_H__ */
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#ifndef __CONSOLE_H__ #ifndef __CONSOLE_H__
#define __CONSOLE_H__ #define __CONSOLE_H__
void console_init(unsigned long base_addr); int console_init(unsigned long base_addr,
unsigned int uart_clk, unsigned int baud_rate);
int console_putc(int c); int console_putc(int c);
int console_getc(void); int console_getc(void);
......
...@@ -72,6 +72,8 @@ uint32_t plat_interrupt_type_to_line(uint32_t type, ...@@ -72,6 +72,8 @@ uint32_t plat_interrupt_type_to_line(uint32_t type,
unsigned int platform_get_core_pos(unsigned long mpidr); unsigned int platform_get_core_pos(unsigned long mpidr);
unsigned long platform_get_stack(unsigned long mpidr); unsigned long platform_get_stack(unsigned long mpidr);
void plat_report_exception(unsigned long); void plat_report_exception(unsigned long);
void plat_crash_console_init(unsigned long base_addr);
int plat_crash_console_putc(int c);
/******************************************************************************* /*******************************************************************************
* Mandatory BL1 functions * Mandatory BL1 functions
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <arch.h> #include <arch.h>
#include <asm_macros.S> #include <asm_macros.S>
#include <assert_macros.S>
.globl get_afflvl_shift .globl get_afflvl_shift
.globl mpidr_mask_lower_afflvls .globl mpidr_mask_lower_afflvls
...@@ -46,7 +47,6 @@ ...@@ -46,7 +47,6 @@
.globl enable_vfp .globl enable_vfp
#endif #endif
func get_afflvl_shift func get_afflvl_shift
cmp x0, #3 cmp x0, #3
cinc x0, x0, eq cinc x0, x0, eq
...@@ -79,6 +79,10 @@ func smc ...@@ -79,6 +79,10 @@ func smc
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
*/ */
func zeromem16 func zeromem16
#if ASM_ASSERTION
tst x0, #0xf
ASM_ASSERT(eq)
#endif
add x2, x0, x1 add x2, x0, x1
/* zero 16 bytes at a time */ /* zero 16 bytes at a time */
z_loop16: z_loop16:
...@@ -105,6 +109,11 @@ z_end: ret ...@@ -105,6 +109,11 @@ z_end: ret
* -------------------------------------------------------------------------- * --------------------------------------------------------------------------
*/ */
func memcpy16 func memcpy16
#if ASM_ASSERTION
orr x3, x0, x1
tst x3, #0xf
ASM_ASSERT(eq)
#endif
/* copy 16 bytes at a time */ /* copy 16 bytes at a time */
m_loop16: m_loop16:
cmp x2, #16 cmp x2, #16
...@@ -145,7 +154,6 @@ func disable_mmu_icache_el3 ...@@ -145,7 +154,6 @@ func disable_mmu_icache_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT) mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
b do_disable_mmu b do_disable_mmu
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
* Enable the use of VFP at EL3 * Enable the use of VFP at EL3
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment