diff options
69 files changed, 2473 insertions, 365 deletions
@@ -488,6 +488,7 @@ $(eval $(call assert_boolean,GENERATE_COT)) $(eval $(call assert_boolean,GICV2_G0_FOR_EL3)) $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY)) $(eval $(call assert_boolean,LOAD_IMAGE_V2)) +$(eval $(call assert_boolean,MULTI_CONSOLE_API)) $(eval $(call assert_boolean,NS_TIMER_SWITCH)) $(eval $(call assert_boolean,PL011_GENERIC_UART)) $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS)) @@ -500,6 +501,7 @@ $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT)) $(eval $(call assert_boolean,USE_COHERENT_MEM)) $(eval $(call assert_boolean,USE_TBBR_DEFS)) $(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY)) +$(eval $(call assert_boolean,BL2_AT_EL3)) $(eval $(call assert_numeric,ARM_ARCH_MAJOR)) $(eval $(call assert_numeric,ARM_ARCH_MINOR)) @@ -529,6 +531,7 @@ $(eval $(call add_define,GICV2_G0_FOR_EL3)) $(eval $(call add_define,HW_ASSISTED_COHERENCY)) $(eval $(call add_define,LOAD_IMAGE_V2)) $(eval $(call add_define,LOG_LEVEL)) +$(eval $(call add_define,MULTI_CONSOLE_API)) $(eval $(call add_define,NS_TIMER_SWITCH)) $(eval $(call add_define,PL011_GENERIC_UART)) $(eval $(call add_define,PLAT_${PLAT})) @@ -543,6 +546,7 @@ $(eval $(call add_define,TRUSTED_BOARD_BOOT)) $(eval $(call add_define,USE_COHERENT_MEM)) $(eval $(call add_define,USE_TBBR_DEFS)) $(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY)) +$(eval $(call add_define,BL2_AT_EL3)) # Define the EL3_PAYLOAD_BASE flag only if it is provided. ifdef EL3_PAYLOAD_BASE @@ -584,8 +588,12 @@ $(eval $(call MAKE_BL,1)) endif ifeq (${NEED_BL2},yes) -$(if ${BL2}, $(eval $(call MAKE_TOOL_ARGS,2,${BL2},tb-fw)),\ - $(eval $(call MAKE_BL,2,tb-fw))) +ifeq (${BL2_AT_EL3}, 0) +FIP_BL2_ARGS := tb-fw +endif + +$(if ${BL2}, $(eval $(call MAKE_TOOL_ARGS,2,${BL2},${FIP_BL2_ARGS})),\ + $(eval $(call MAKE_BL,2,${FIP_BL2_ARGS}))) endif ifeq (${NEED_SCP_BL2},yes) @@ -13,7 +13,10 @@ BL1_SOURCES += bl1/bl1_main.c \ lib/cpus/errata_report.c \ lib/el3_runtime/${ARCH}/context_mgmt.c \ plat/common/plat_bl1_common.c \ - plat/common/${ARCH}/platform_up_stack.S + plat/common/${ARCH}/platform_up_stack.S \ + ${MBEDTLS_COMMON_SOURCES} \ + ${MBEDTLS_CRYPTO_SOURCES} \ + ${MBEDTLS_X509_SOURCES} ifeq (${ARCH},aarch64) BL1_SOURCES += lib/el3_runtime/aarch64/context.S diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S new file mode 100644 index 00000000..997b069c --- /dev/null +++ b/bl2/aarch32/bl2_el3_entrypoint.S @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> +#include <el3_common_macros.S> + + + .globl bl2_entrypoint + .globl bl2_run_next_image + + +func bl2_entrypoint + /* Save arguments x0-x3 from previous Boot loader */ + mov r9, r0 + mov r10, r1 + mov r11, r2 + mov r12, r3 + + el3_entrypoint_common \ + _init_sctlr=1 \ + _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ + _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ + _init_memory=1 \ + _init_c_runtime=1 \ + _exception_vectors=bl2_vector_table + + /* + * Restore parameters of boot rom + */ + mov r0, r9 + mov r1, r10 + mov r2, r11 + mov r3, r12 + + bl bl2_el3_early_platform_setup + bl bl2_el3_plat_arch_setup + + /* --------------------------------------------- + * Jump to main function. + * --------------------------------------------- + */ + bl bl2_main + + /* --------------------------------------------- + * Should never reach this point. + * --------------------------------------------- + */ + no_ret plat_panic_handler + +endfunc bl2_entrypoint + +func bl2_run_next_image + mov r8,r0 + + /* + * MMU needs to be disabled because both BL2 and BL32 execute + * in PL1, and therefore share the same address space. + * BL32 will initialize the address space according to its + * own requirement. + */ + bl disable_mmu_icache_secure + stcopr r0, TLBIALL + dsb sy + isb + mov r0, r8 + bl bl2_el3_plat_prepare_exit + + /* + * Extract PC and SPSR based on struct `entry_point_info_t` + * and load it in LR and SPSR registers respectively. + */ + ldr lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET] + ldr r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)] + msr spsr, r1 + + add r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET + ldm r8, {r0, r1, r2, r3} + eret +endfunc bl2_run_next_image diff --git a/bl2/aarch32/bl2_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S new file mode 100644 index 00000000..11ddf371 --- /dev/null +++ b/bl2/aarch32/bl2_el3_exceptions.S @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> + + .globl bl2_vector_table + +vector_base bl2_vector_table + b bl2_entrypoint + b report_exception /* Undef */ + b report_exception /* SVC call */ + b report_exception /* Prefetch abort */ + b report_exception /* Data abort */ + b report_exception /* Reserved */ + b report_exception /* IRQ */ + b report_exception /* FIQ */ diff --git a/bl2/aarch64/bl2_el3_entrypoint.S b/bl2/aarch64/bl2_el3_entrypoint.S new file mode 100644 index 00000000..2d3efd1f --- /dev/null +++ b/bl2/aarch64/bl2_el3_entrypoint.S @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> +#include <el3_common_macros.S> + + .globl bl2_entrypoint + .globl bl2_vector_table + .globl bl2_el3_run_image + .globl bl2_run_next_image + +func bl2_entrypoint + /* Save arguments x0-x3 from previous Boot loader */ + mov x20, x0 + mov x21, x1 + mov x22, x2 + mov x23, x3 + + el3_entrypoint_common \ + _init_sctlr=1 \ + _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ + _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ + _init_memory=1 \ + _init_c_runtime=1 \ + _exception_vectors=bl2_el3_exceptions + + /* + * Restore parameters of boot rom + */ + mov x0, x20 + mov x1, x21 + mov x2, x22 + mov x3, x23 + + bl bl2_el3_early_platform_setup + bl bl2_el3_plat_arch_setup + + /* --------------------------------------------- + * Jump to main function. + * --------------------------------------------- + */ + bl bl2_main + + /* --------------------------------------------- + * Should never reach this point. + * --------------------------------------------- + */ + no_ret plat_panic_handler +endfunc bl2_entrypoint + +func bl2_run_next_image + mov x20,x0 + /* + * MMU needs to be disabled because both BL2 and BL31 execute + * in EL3, and therefore share the same address space. + * BL31 will initialize the address space according to its + * own requirement. + */ + bl disable_mmu_icache_el3 + tlbi alle3 + bl bl2_el3_plat_prepare_exit + + ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] + msr elr_el3, x0 + msr spsr_el3, x1 + + ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)] + ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)] + ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)] + ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)] + eret +endfunc bl2_run_next_image diff --git a/bl2/aarch64/bl2_el3_exceptions.S b/bl2/aarch64/bl2_el3_exceptions.S new file mode 100644 index 00000000..987f6e35 --- /dev/null +++ b/bl2/aarch64/bl2_el3_exceptions.S @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl1.h> +#include <bl_common.h> +#include <context.h> + +/* ----------------------------------------------------------------------------- + * Very simple stackless exception handlers used by BL2. + * ----------------------------------------------------------------------------- + */ + .globl bl2_el3_exceptions + +vector_base bl2_el3_exceptions + + /* ----------------------------------------------------- + * Current EL with SP0 : 0x0 - 0x200 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionSP0 + mov x0, #SYNC_EXCEPTION_SP_EL0 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SynchronousExceptionSP0 + +vector_entry IrqSP0 + mov x0, #IRQ_SP_EL0 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size IrqSP0 + +vector_entry FiqSP0 + mov x0, #FIQ_SP_EL0 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size FiqSP0 + +vector_entry SErrorSP0 + mov x0, #SERROR_SP_EL0 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SErrorSP0 + + /* ----------------------------------------------------- + * Current EL with SPx: 0x200 - 0x400 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionSPx + mov x0, #SYNC_EXCEPTION_SP_ELX + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SynchronousExceptionSPx + +vector_entry IrqSPx + mov x0, #IRQ_SP_ELX + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size IrqSPx + +vector_entry FiqSPx + mov x0, #FIQ_SP_ELX + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size FiqSPx + +vector_entry SErrorSPx + mov x0, #SERROR_SP_ELX + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SErrorSPx + + /* ----------------------------------------------------- + * Lower EL using AArch64 : 0x400 - 0x600 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionA64 + mov x0, #SYNC_EXCEPTION_AARCH64 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SynchronousExceptionA64 + +vector_entry IrqA64 + mov x0, #IRQ_AARCH64 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size IrqA64 + +vector_entry FiqA64 + mov x0, #FIQ_AARCH64 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size FiqA64 + +vector_entry SErrorA64 + mov x0, #SERROR_AARCH64 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SErrorA64 + + /* ----------------------------------------------------- + * Lower EL using AArch32 : 0x600 - 0x800 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionA32 + mov x0, #SYNC_EXCEPTION_AARCH32 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SynchronousExceptionA32 + +vector_entry IrqA32 + mov x0, #IRQ_AARCH32 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size IrqA32 + +vector_entry FiqA32 + mov x0, #FIQ_AARCH32 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size FiqA32 + +vector_entry SErrorA32 + mov x0, #SERROR_AARCH32 + bl plat_report_exception + no_ret plat_panic_handler + check_vector_size SErrorA32 @@ -5,10 +5,12 @@ # BL2_SOURCES += bl2/bl2_main.c \ - bl2/${ARCH}/bl2_entrypoint.S \ bl2/${ARCH}/bl2_arch_setup.c \ lib/locks/exclusive/${ARCH}/spinlock.S \ - plat/common/${ARCH}/platform_up_stack.S + plat/common/${ARCH}/platform_up_stack.S \ + ${MBEDTLS_COMMON_SOURCES} \ + ${MBEDTLS_CRYPTO_SOURCES} \ + ${MBEDTLS_X509_SOURCES} ifeq (${ARCH},aarch64) BL2_SOURCES += common/aarch64/early_exceptions.S @@ -20,4 +22,15 @@ else BL2_SOURCES += bl2/bl2_image_load.c endif +ifeq (${BL2_AT_EL3},0) +BL2_SOURCES += bl2/${ARCH}/bl2_entrypoint.S BL2_LINKERFILE := bl2/bl2.ld.S + +else +BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \ + bl2/${ARCH}/bl2_el3_exceptions.S \ + plat/common/plat_bl2_el3_common.c \ + lib/cpus/${ARCH}/cpu_helpers.S \ + lib/cpus/errata_report.c +BL2_LINKERFILE := bl2/bl2_el3.ld.S +endif diff --git a/bl2/bl2_el3.ld.S b/bl2/bl2_el3.ld.S new file mode 100644 index 00000000..57709e35 --- /dev/null +++ b/bl2/bl2_el3.ld.S @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> +#include <xlat_tables_defs.h> + +OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) +OUTPUT_ARCH(PLATFORM_LINKER_ARCH) +ENTRY(bl2_entrypoint) + +MEMORY { + RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE +} + + +SECTIONS +{ + . = BL2_BASE; + ASSERT(. == ALIGN(PAGE_SIZE), + "BL2_BASE address is not aligned on a page boundary.") + +#if SEPARATE_CODE_AND_RODATA + .text . : { + __TEXT_START__ = .; + __TEXT_RESIDENT_START__ = .; + *bl2_el3_entrypoint.o(.text*) + *(.text.asm.*) + __TEXT_RESIDENT_END__ = .; + *(.text*) + *(.vectors) + . = NEXT(PAGE_SIZE); + __TEXT_END__ = .; + } >RAM + + .rodata . : { + __RODATA_START__ = .; + *(.rodata*) + + /* Ensure 8-byte alignment for descriptors and ensure inclusion */ + . = ALIGN(8); + __PARSER_LIB_DESCS_START__ = .; + KEEP(*(.img_parser_lib_descs)) + __PARSER_LIB_DESCS_END__ = .; + + /* + * Ensure 8-byte alignment for cpu_ops so that its fields are also + * aligned. Also ensure cpu_ops inclusion. + */ + . = ALIGN(8); + __CPU_OPS_START__ = .; + KEEP(*(cpu_ops)) + __CPU_OPS_END__ = .; + + . = NEXT(PAGE_SIZE); + __RODATA_END__ = .; + } >RAM + + ASSERT(__TEXT_RESIDENT_END__ - __TEXT_RESIDENT_START__ <= PAGE_SIZE, + "Resident part of BL2 has exceeded its limit.") +#else + ro . : { + __RO_START__ = .; + __TEXT_RESIDENT_START__ = .; + *bl2_el3_entrypoint.o(.text*) + *(.text.asm.*) + __TEXT_RESIDENT_END__ = .; + *(.text*) + *(.rodata*) + + /* + * Ensure 8-byte alignment for cpu_ops so that its fields are also + * aligned. Also ensure cpu_ops inclusion. + */ + . = ALIGN(8); + __CPU_OPS_START__ = .; + KEEP(*(cpu_ops)) + __CPU_OPS_END__ = .; + + /* Ensure 8-byte alignment for descriptors and ensure inclusion */ + . = ALIGN(8); + __PARSER_LIB_DESCS_START__ = .; + KEEP(*(.img_parser_lib_descs)) + __PARSER_LIB_DESCS_END__ = .; + + *(.vectors) + __RO_END_UNALIGNED__ = .; + /* + * Memory page(s) mapped to this section will be marked as + * read-only, executable. No RW data from the next section must + * creep in. Ensure the rest of the current memory page is unused. + */ + . = NEXT(PAGE_SIZE); + + __RO_END__ = .; + } >RAM +#endif + + ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, + "cpu_ops not defined for this platform.") + + /* + * Define a linker symbol to mark start of the RW memory area for this + * image. + */ + __RW_START__ = . ; + + /* + * .data must be placed at a lower address than the stacks if the stack + * protector is enabled. Alternatively, the .data.stack_protector_canary + * section can be placed independently of the main .data section. + */ + .data . : { + __DATA_START__ = .; + *(.data*) + __DATA_END__ = .; + } >RAM + + stacks (NOLOAD) : { + __STACKS_START__ = .; + *(tzfw_normal_stacks) + __STACKS_END__ = .; + } >RAM + + /* + * The .bss section gets initialised to 0 at runtime. + * Its base address should be 16-byte aligned for better performance of the + * zero-initialization code. + */ + .bss : ALIGN(16) { + __BSS_START__ = .; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + __BSS_END__ = .; + } >RAM + + /* + * The xlat_table section is for full, aligned page tables (4K). + * Removing them from .bss avoids forcing 4K alignment on + * the .bss section and eliminates the unnecessary zero init + */ + xlat_table (NOLOAD) : { + *(xlat_table) + } >RAM + +#if USE_COHERENT_MEM + /* + * The base address of the coherent memory section must be page-aligned (4K) + * to guarantee that the coherent data are stored on their own pages and + * are not mixed with normal data. This is required to set up the correct + * memory attributes for the coherent data page tables. + */ + coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { + __COHERENT_RAM_START__ = .; + *(tzfw_coherent_mem) + __COHERENT_RAM_END_UNALIGNED__ = .; + /* + * Memory page(s) mapped to this section will be marked + * as device memory. No other unexpected data must creep in. + * Ensure the rest of the current memory page is unused. + */ + . = NEXT(PAGE_SIZE); + __COHERENT_RAM_END__ = .; + } >RAM +#endif + + /* + * Define a linker symbol to mark end of the RW memory area for this + * image. + */ + __RW_END__ = .; + __BL2_END__ = .; + + __BSS_SIZE__ = SIZEOF(.bss); + +#if USE_COHERENT_MEM + __COHERENT_RAM_UNALIGNED_SIZE__ = + __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; +#endif + + ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.") +} diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c index 018deb34..c85db2d4 100644 --- a/bl2/bl2_main.c +++ b/bl2/bl2_main.c @@ -13,6 +13,11 @@ #include <platform.h> #include "bl2_private.h" +#ifdef AARCH32 +#define NEXT_IMAGE "BL32" +#else +#define NEXT_IMAGE "BL31" +#endif /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to @@ -49,6 +54,8 @@ void bl2_main(void) disable_mmu_icache_secure(); #endif /* AARCH32 */ + +#if !BL2_AT_EL3 console_flush(); /* @@ -57,4 +64,11 @@ void bl2_main(void) * be passed to next BL image as an argument. */ smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0); +#else + NOTICE("BL2: Booting " NEXT_IMAGE "\n"); + print_entry_point_info(next_bl_ep_info); + console_flush(); + + bl2_run_next_image(next_bl_ep_info); +#endif } diff --git a/bl2/bl2_private.h b/bl2/bl2_private.h index 83b8047a..ea2f33aa 100644 --- a/bl2/bl2_private.h +++ b/bl2/bl2_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -17,5 +17,6 @@ struct entry_point_info; *****************************************/ void bl2_arch_setup(void); struct entry_point_info *bl2_load_images(void); +void bl2_run_next_image(const entry_point_info_t *bl_ep_info); #endif /* __BL2_PRIVATE_H__ */ diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S index cf32b31d..0986a0a1 100644 --- a/bl31/aarch64/crash_reporting.S +++ b/bl31/aarch64/crash_reporting.S @@ -9,13 +9,13 @@ #include <cpu_data.h> #include <plat_macros.S> #include <platform_def.h> +#include <utils_def.h> .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 @@ -92,7 +92,7 @@ test_size_list: mov x6, x4 adr x4, print_spacer bl asm_print_str - ldr x4, [x7], #REG_SIZE + ldr x4, [x7], #REGSZ bl asm_print_hex bl print_newline b test_size_list @@ -114,9 +114,9 @@ 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] + 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 @@ -136,7 +136,7 @@ endfunc str_in_crash_buf_print add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET /* Store crash buffer address in tpidr_el3 */ msr tpidr_el3, x0 - str x1, [x0, #REG_SIZE] + str x1, [x0, #REGSZ] mov x1, sp str x1, [x0] .endm @@ -214,9 +214,9 @@ 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] + 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 */ @@ -227,13 +227,13 @@ func do_crash_reporting /* load the crash buf address */ mrs x0, tpidr_el3 /* report x30 first from the crash buf */ - ldr x4, [x0, #REG_SIZE * 7] + ldr x4, [x0, #REGSZ * 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] + str x7, [x0, #REGSZ * 7] /* Report x0 - x29 values stored in crash buf*/ /* Store the ascii list pointer in x6 */ @@ -246,15 +246,15 @@ func do_crash_reporting 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] + 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, #REG_SIZE * 2] - stp x28, x29, [x0, #REG_SIZE * 4] + stp x26, x27, [x0, #REGSZ * 2] + stp x28, x29, [x0, #REGSZ * 4] bl size_controlled_print /* Print the el3 sys registers */ diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst index 3cb004a4..1f8fcc86 100644 --- a/docs/firmware-design.rst +++ b/docs/firmware-design.rst @@ -418,6 +418,63 @@ BL2 execution continues as follows: #. BL1 passes control to BL31 at the specified entrypoint at EL3. +Running BL2 at EL3 execution level +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some platforms have a non-TF Boot ROM that expects the next boot stage +to execute at EL3. On these platforms, TF BL1 is a waste of memory +as its only purpose is to ensure TF BL2 is entered at S-EL1. To avoid +this waste, a special mode enables BL2 to execute at EL3, which allows +a non-TF Boot ROM to load and jump directly to BL2. This mode is selected +when the build flag BL2_AT_EL3 is enabled. The main differences in this +mode are: + +#. BL2 includes the reset code and the mailbox mechanism to differentiate + cold boot and warm boot. It runs at EL3 doing the arch + initialization required for EL3. + +#. BL2 does not receive the meminfo information from BL1 anymore. This + information can be passed by the Boot ROM or be internal to the + BL2 image. + +#. Since BL2 executes at EL3, BL2 jumps directly to the next image, + instead of invoking the RUN_IMAGE SMC call. + + +We assume 3 different types of BootROM support on the platform: + +#. The Boot ROM always jumps to the same address, for both cold + and warm boot. In this case, we will need to keep a resident part + of BL2 whose memory cannot be reclaimed by any other image. The + linker script defines the symbols __TEXT_RESIDENT_START__ and + __TEXT_RESIDENT_END__ that allows the platform to configure + correctly the memory map. +#. The platform has some mechanism to indicate the jump address to the + Boot ROM. Platform code can then program the jump address with + psci_warmboot_entrypoint during cold boot. +#. The platform has some mechanism to program the reset address using + the PROGRAMMABLE_RESET_ADDRESS feature. Platform code can then + program the reset address with psci_warmboot_entrypoint during + cold boot, bypassing the boot ROM for warm boot. + +In the last 2 cases, no part of BL2 needs to remain resident at +runtime. In the first 2 cases, we expect the Boot ROM to be able to +differentiate between warm and cold boot, to avoid loading BL2 again +during warm boot. + +This functionality can be tested with FVP loading the image directly +in memory and changing the address where the system jumps at reset. +For example: + + -C cluster0.cpu0.RVBAR=0x4014000 + --data cluster0.cpu0=bl2.bin@0x4014000 + +With this configuration, FVP is like a platform of the first case, +where the Boot ROM jumps always to the same address. For simplification, +BL32 is loaded in DRAM in this case, to avoid other images reclaiming +BL2 memory. + + AArch64 BL31 ~~~~~~~~~~~~ diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 2e2cc4f7..7683ded0 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -1643,6 +1643,70 @@ element in the boot sequence. If there are no more boot sources then it must return 0, otherwise it must return 1. The default implementation of this always returns 0. +Boot Loader Stage 2 (BL2) at EL3 +-------------------------------- + +When the platform has a non-TF Boot ROM it is desirable to jump +directly to BL2 instead of TF BL1. In this case BL2 is expected to +execute at EL3 instead of executing at EL1. Refer to the `Firmware +Design`_ for more information. + +All mandatory functions of BL2 must be implemented, except the functions +bl2\_early\_platform\_setup and bl2\_el3\_plat\_arch\_setup, because +their work is done now by bl2\_el3\_early\_platform\_setup and +bl2\_el3\_plat\_arch\_setup. These functions should generally implement +the bl1\_plat\_xxx() and bl2\_plat\_xxx() functionality combined. + + +Function : bl2\_el3\_early\_platform\_setup() [mandatory] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + Argument : u_register_t, u_register_t, u_register_t, u_register_t + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. This function receives four parameters which can be used +by the platform to pass any needed information from the Boot ROM to BL2. + +On ARM standard platforms, this function does the following: + +- Initializes a UART (PL011 console), which enables access to the ``printf`` + family of functions in BL2. + +- Initializes the storage abstraction layer used to load further bootloader + images. It is necessary to do this early on platforms with a SCP\_BL2 image, + since the later ``bl2_platform_setup`` must be done after SCP\_BL2 is loaded. + +- Initializes the private variables that define the memory layout used. + +Function : bl2\_el3\_plat\_arch\_setup() [mandatory] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + Argument : void + Return : void + +This function executes with the MMU and data caches disabled. It is only called +by the primary CPU. + +The purpose of this function is to perform any architectural initialization +that varies across platforms. + +On ARM standard platforms, this function enables the MMU. + +Function : bl2\_el3\_plat\_prepare\_exit() [optional] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + Argument : void + Return : void + +This function is called prior to exiting BL2 and run the next image. +It should be used to perform platform specific clean up or bookkeeping +operations before transferring control to the next image. This function +runs with MMU disabled. + FWU Boot Loader Stage 2 (BL2U) ------------------------------ @@ -1865,12 +1929,8 @@ Function : bl31\_plat\_runtime\_setup() [optional] The purpose of this function is allow the platform to perform any BL31 runtime setup just prior to BL31 exit during cold boot. The default weak -implementation of this function will invoke ``console_uninit()`` which will -suppress any BL31 runtime logs. - -In ARM Standard platforms, this function will initialize the BL31 runtime -console which will cause all further BL31 logs to be output to the -runtime console. +implementation of this function will invoke ``console_switch_state()`` to switch +console output to consoles marked for use in the ``runtime`` state. Function : bl31\_get\_next\_image\_info() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2638,14 +2698,20 @@ as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt. Crash Reporting mechanism (in BL31) ----------------------------------- +NOTE: This section assumes that your platform is enabling the MULTI_CONSOLE_API +flag in its platform.mk. Not using this flag is deprecated for new platforms. + BL31 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 be used to -print the register dump. +of the CPU to enable quick crash analysis and debugging. By default, the +definitions in ``plat/common/aarch64/platform\_helpers.S`` will cause the crash +output to be routed over the normal console infrastructure and get printed on +consoles configured to output in crash state. ``console_set_scope()`` can be +used to control whether a console is used for crash output. -The following functions must be implemented by the platform if it wants crash -reporting mechanism in BL31. The functions are implemented in assembly so that -they can be invoked without a C Runtime stack. +In some cases (such as debugging very early crashes that happen before the +normal boot console can be set up), platforms may want to control crash output +more explicitly. For these, the following functions can be overridden by +platform code. They are executed outside of a C environment and without a stack. Function : plat\_crash\_console\_init ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2656,9 +2722,30 @@ Function : plat\_crash\_console\_init Return : int This API is used by the crash reporting mechanism to initialize the crash -console. It must only use the general purpose registers x0 to x4 to do the +console. It must only use the general purpose registers x0 through x7 to do the initialization and returns 1 on success. +If you are trying to debug crashes before the console driver would normally get +registered, you can use this to register a driver from assembly with hardcoded +parameters. For example, you could register the 16550 driver like this: + +:: + + .section .data.crash_console /* Reserve space for console structure */ + crash_console: + .zero 6 * 8 /* console_16550_t has 6 8-byte words */ + func plat_crash_console_init + ldr x0, =YOUR_16550_BASE_ADDR + ldr x1, =YOUR_16550_SRCCLK_IN_HZ + ldr x2, =YOUR_16550_TARGET_BAUD_RATE + adrp x3, crash_console + add x3, x3, :lo12:crash_console + b console_16550_register /* tail call, returns 1 on success */ + endfunc plat_crash_console_init + +If you're trying to debug crashes in BL1, you can call the console_xxx_core_init +function exported by some console drivers from here. + Function : plat\_crash\_console\_putc ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2672,6 +2759,12 @@ designated crash console. It must only use general purpose registers x1 and x2 to do its work. The parameter and the return value are in general purpose register x0. +If you have registered a normal console driver in ``plat_crash_console_init``, +you can keep the default implementation here (which calls ``console_putc()``). + +If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc +function exported by some console drivers from here. + Function : plat\_crash\_console\_flush ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2682,9 +2775,15 @@ Function : plat\_crash\_console\_flush This API is used by the crash reporting mechanism to force write of all buffered data on the designated crash console. It should only use general purpose -registers x0 and x1 to do its work. The return value is 0 on successful +registers x0 through x5 to do its work. The return value is 0 on successful completion; otherwise the return value is -1. +If you have registered a normal console driver in ``plat_crash_console_init``, +you can keep the default implementation here (which calls ``console_flush()``). + +If you're trying to debug crashes in BL1, you can call the console_xx_core_flush +function exported by some console drivers from here. + Build flags ----------- diff --git a/docs/user-guide.rst b/docs/user-guide.rst index 0647e705..ed5ba184 100644 --- a/docs/user-guide.rst +++ b/docs/user-guide.rst @@ -245,6 +245,9 @@ Common build options BL2U image. In this case, the BL2U in the ARM Trusted Firmware will not be built. +- ``BL2_AT_EL3``: This is an optional build option that enables the use of + BL2 at EL3 execution level. + - ``BL31``: This is an optional build option which specifies the path to BL31 image for the ``fip`` target. In this case, the BL31 in the ARM Trusted Firmware will not be built. diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S index 8b15d565..6f2510ad 100644 --- a/drivers/arm/pl011/aarch64/pl011_console.S +++ b/drivers/arm/pl011/aarch64/pl011_console.S @@ -5,6 +5,7 @@ */ #include <arch.h> #include <asm_macros.S> +#include <assert_macros.S> #include <pl011.h> /* @@ -13,15 +14,21 @@ */ #include "../../../console/aarch64/console.S" + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_pl011_core_init + .globl console_pl011_core_putc + .globl console_pl011_core_getc + .globl console_pl011_core_flush - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush - + .globl console_pl011_putc + .globl console_pl011_getc + .globl console_pl011_flush /* ----------------------------------------------- - * int console_core_init(uintptr_t base_addr, + * int console_pl011_core_init(uintptr_t base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This @@ -34,7 +41,7 @@ * Clobber list : x1, x2, x3, x4 * ----------------------------------------------- */ -func console_core_init +func console_pl011_core_init /* Check the input base address */ cbz x0, core_init_fail #if !PL011_GENERIC_UART @@ -71,10 +78,54 @@ func console_core_init core_init_fail: mov w0, wzr ret -endfunc console_core_init +endfunc console_pl011_core_init + +#if MULTI_CONSOLE_API + .globl console_pl011_register + + /* ----------------------------------------------- + * int console_pl011_register(console_pl011_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new PL011 + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * w1 - UART clock in Hz + * w2 - Baud rate + * x3 - pointer to empty console_pl011_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_pl011_register + mov x7, x30 + mov x6, x3 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_PL011_BASE] + + bl console_pl011_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, x7 + finish_console_register pl011 + +register_fail: + ret x7 +endfunc console_pl011_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_pl011_core_init + .equ console_core_putc,console_pl011_core_putc + .equ console_core_getc,console_pl011_core_getc + .equ console_core_flush,console_pl011_core_flush +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, uintptr_t base_addr) + * int console_pl011_core_putc(int c, uintptr_t 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 @@ -83,9 +134,12 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_pl011_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f @@ -101,36 +155,75 @@ func console_core_putc tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b str w0, [x1, #UARTDR] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_pl011_core_putc + + /* -------------------------------------------------------- + * int console_pl011_putc(int c, console_pl011_t *console) + * 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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_pl011_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_PL011_BASE] + b console_pl011_core_putc +endfunc console_pl011_putc /* --------------------------------------------- - * int console_core_getc(uintptr_t base_addr) + * int console_pl011_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. + * or -1 if no character is available. * In : x0 - console base address + * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error -1: +func console_pl011_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ ldr w1, [x0, #UARTFR] - tbnz w1, #PL011_UARTFR_RXFE_BIT, 1b + tbnz w1, #PL011_UARTFR_RXFE_BIT, no_char ldr w1, [x0, #UARTDR] mov w0, w1 ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_pl011_core_getc + + /* --------------------------------------------- + * int console_pl011_getc(console_pl011_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 if no character is available. + * In : x0 - pointer to console_t structure + * Out: w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_pl011_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_PL011_BASE] + b console_pl011_core_getc +endfunc console_pl011_getc /* --------------------------------------------- - * int console_core_flush(uintptr_t base_addr) + * int console_pl011_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address @@ -138,9 +231,11 @@ endfunc console_core_getc * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_flush - cbz x0, flush_error - +func console_pl011_core_flush +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ 1: /* Loop until the transmit FIFO is empty */ ldr w1, [x0, #UARTFR] @@ -148,7 +243,22 @@ func console_core_flush mov w0, #0 ret -flush_error: - mov w0, #-1 - ret -endfunc console_core_flush +endfunc console_pl011_core_flush + + /* --------------------------------------------- + * int console_pl011_flush(console_pl011_t *console) + * Function to force a write of all buffered + * data that hasn't been output. + * In : x0 - pointer to console_t structure + * Out : return -1 on error else return 0. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_pl011_flush +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_PL011_BASE] + b console_pl011_core_flush +endfunc console_pl011_flush diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk index f2b6f6e5..8c4123db 100644 --- a/drivers/auth/mbedtls/mbedtls_common.mk +++ b/drivers/auth/mbedtls/mbedtls_common.mk @@ -29,7 +29,4 @@ MBEDTLS_COMMON_SOURCES := drivers/auth/mbedtls/mbedtls_common.c \ platform.c \ ) -BL1_SOURCES += ${MBEDTLS_COMMON_SOURCES} -BL2_SOURCES += ${MBEDTLS_COMMON_SOURCES} - endif diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk index 8eb4873d..6b15e717 100644 --- a/drivers/auth/mbedtls/mbedtls_crypto.mk +++ b/drivers/auth/mbedtls/mbedtls_crypto.mk @@ -89,6 +89,3 @@ endif # Needs to be set to drive mbed TLS configuration correctly $(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID)) $(eval $(call add_define,TF_MBEDTLS_HASH_ALG_ID)) - -BL1_SOURCES += ${MBEDTLS_CRYPTO_SOURCES} -BL2_SOURCES += ${MBEDTLS_CRYPTO_SOURCES} diff --git a/drivers/auth/mbedtls/mbedtls_x509.mk b/drivers/auth/mbedtls/mbedtls_x509.mk index 0f28b651..a6f72e67 100644 --- a/drivers/auth/mbedtls/mbedtls_x509.mk +++ b/drivers/auth/mbedtls/mbedtls_x509.mk @@ -11,6 +11,3 @@ MBEDTLS_X509_SOURCES := drivers/auth/mbedtls/mbedtls_x509_parser.c \ x509.c \ x509_crt.c \ ) - -BL1_SOURCES += ${MBEDTLS_X509_SOURCES} -BL2_SOURCES += ${MBEDTLS_X509_SOURCES} diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S index f6a1532c..fc357f8a 100644 --- a/drivers/cadence/uart/aarch64/cdns_console.S +++ b/drivers/cadence/uart/aarch64/cdns_console.S @@ -5,16 +5,22 @@ */ #include <arch.h> #include <asm_macros.S> +#include <assert_macros.S> #include <cadence/cdns_uart.h> - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_cdns_core_init + .globl console_cdns_core_putc + .globl console_cdns_core_getc + + .globl console_cdns_putc + .globl console_cdns_getc /* ----------------------------------------------- - * int console_core_init(unsigned long base_addr, - * unsigned int uart_clk, unsigned int baud_rate) + * int console_cdns_core_init(uintptr_t base_addr) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_init and @@ -23,18 +29,13 @@ * the HW (baud, ...) and only enable the trans- * mitter and receiver here. * In: x0 - console base address - * w1 - Uart clock in Hz - * w2 - Baud rate * Out: return 1 on success else 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ -func console_core_init +func console_cdns_core_init /* Check the input base address */ cbz x0, core_init_fail - /* Check baud rate and uart clock for sanity */ - cbz w1, core_init_fail - cbz w2, core_init_fail /* RX/TX enabled & reset */ mov w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST) @@ -45,10 +46,51 @@ func console_core_init core_init_fail: mov w0, wzr ret -endfunc console_core_init +endfunc console_cdns_core_init + +#if MULTI_CONSOLE_API + .globl console_cdns_register + + /* ----------------------------------------------- + * int console_cdns_register(console_cdns_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new CDNS + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * x1 - pointer to empty console_cdns_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_cdns_register + mov x7, x30 + mov x6, x1 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_CDNS_BASE] + + bl console_cdns_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, v7 + finish_console_register cdns + +register_fail: + ret x7 +endfunc console_cdns_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_cdns_core_init + .equ console_core_putc,console_cdns_core_putc + .equ console_core_getc,console_cdns_core_getc +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, unsigned long base_addr) + * int console_cdns_core_putc(int c, uintptr_t 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 @@ -57,9 +99,12 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_cdns_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f @@ -75,36 +120,76 @@ func console_core_putc tbnz w2, #UART_SR_INTR_TFUL_BIT, 2b str w0, [x1, #R_UART_TX] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_cdns_core_putc + + /* -------------------------------------------------------- + * int console_cdns_putc(int c, console_cdns_t *cdns) + * 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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_cdns_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_CDNS_BASE] + b console_cdns_core_putc +endfunc console_cdns_putc /* --------------------------------------------- - * int console_core_getc(unsigned long base_addr) + * int console_cdns_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. + * or -1 if no character is available. * In : x0 - console base address + * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error -1: +func console_cdns_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ ldr w1, [x0, #R_UART_SR] - tbnz w1, #UART_SR_INTR_REMPTY_BIT, 1b + tbnz w1, #UART_SR_INTR_REMPTY_BIT, no_char ldr w1, [x0, #R_UART_RX] mov w0, w1 ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_cdns_core_getc + + /* --------------------------------------------- + * int console_cdns_getc(console_cdns_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 if no character is available. + * In : x0 - pointer to console_t structure + * Out: w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_cdns_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_CDNS_BASE] + b console_cdns_core_getc +endfunc console_cdns_getc /* --------------------------------------------- * int console_core_flush(uintptr_t base_addr) + * DEPRECATED: Not used with MULTI_CONSOLE_API! * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address diff --git a/drivers/console/aarch64/console.S b/drivers/console/aarch64/console.S index 7cc04ddd..f847ed59 100644 --- a/drivers/console/aarch64/console.S +++ b/drivers/console/aarch64/console.S @@ -1,105 +1,11 @@ /* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#include <asm_macros.S> - .globl console_init - .globl console_uninit - .globl console_putc - .globl console_getc - .globl console_flush - - /* - * 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(uintptr_t 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 else 0 on error - * Clobber list : x1 - x4 - * ----------------------------------------------- - */ -func console_init - /* Check the input base address */ - cbz x0, init_fail - adrp x3, console_base - str x0, [x3, :lo12:console_base] - b console_core_init -init_fail: - ret -endfunc console_init - - /* ----------------------------------------------- - * void console_uninit(void) - * Function to finish the use of console driver. - * It sets the console_base as NULL so that any - * further invocation of `console_putc` or - * `console_getc` APIs would return error. - * ----------------------------------------------- - */ -func console_uninit - mov x0, #0 - adrp x3, console_base - str x0, [x3, :lo12:console_base] - ret -endfunc console_uninit - - /* --------------------------------------------- - * 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 -endfunc console_putc - - /* --------------------------------------------- - * 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 x1, console_base - ldr x0, [x1, :lo12:console_base] - b console_core_getc -endfunc console_getc - - /* --------------------------------------------- - * int console_flush(void) - * Function to force a write of all buffered - * data that hasn't been output. It returns 0 - * upon successful completion, otherwise it - * returns -1. - * Clobber list : x0, x1 - * --------------------------------------------- - */ -func console_flush - adrp x1, console_base - ldr x0, [x1, :lo12:console_base] - b console_core_flush -endfunc console_flush +#if MULTI_CONSOLE_API +#include "multi_console.S" +#else +#include "deprecated_console.S" +#endif diff --git a/drivers/console/aarch64/deprecated_console.S b/drivers/console/aarch64/deprecated_console.S new file mode 100644 index 00000000..c83e2467 --- /dev/null +++ b/drivers/console/aarch64/deprecated_console.S @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <asm_macros.S> + +/* + * This is the common console core code for the deprecated single-console API. + * New platforms should set MULTI_CONSOLE_API=1 and not use this file. + */ + + .globl console_init + .globl console_uninit + .globl console_putc + .globl console_getc + .globl console_flush + + /* + * 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(uintptr_t 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 else 0 on error + * Clobber list : x1 - x4 + * ----------------------------------------------- + */ +func console_init + /* Check the input base address */ + cbz x0, init_fail + adrp x3, console_base + str x0, [x3, :lo12:console_base] + b console_core_init +init_fail: + ret +endfunc console_init + + /* ----------------------------------------------- + * void console_uninit(void) + * Function to finish the use of console driver. + * It sets the console_base as NULL so that any + * further invocation of `console_putc` or + * `console_getc` APIs would return error. + * ----------------------------------------------- + */ +func console_uninit + mov x0, #0 + adrp x3, console_base + str x0, [x3, :lo12:console_base] + ret +endfunc console_uninit + + /* --------------------------------------------- + * 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 +endfunc console_putc + + /* --------------------------------------------- + * 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 x1, console_base + ldr x0, [x1, :lo12:console_base] + b console_core_getc +endfunc console_getc + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. It returns 0 + * upon successful completion, otherwise it + * returns -1. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_flush + adrp x1, console_base + ldr x0, [x1, :lo12:console_base] + b console_core_flush +endfunc console_flush diff --git a/drivers/console/aarch64/multi_console.S b/drivers/console/aarch64/multi_console.S new file mode 100644 index 00000000..15c3ba43 --- /dev/null +++ b/drivers/console/aarch64/multi_console.S @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <assert_macros.S> +#include <console.h> + + .globl console_register + .globl console_unregister + .globl console_set_scope + .globl console_switch_state + .globl console_putc + .globl console_getc + .globl console_flush + + /* + * The console list pointer 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_list ; .align 3 + console_list: .quad 0x0 +.section .data.console_state ; .align 0 + console_state: .byte CONSOLE_FLAG_BOOT + + /* ----------------------------------------------- + * int console_register(console_t *console) + * Function to insert a new console structure into + * the console list. Should usually be called by + * console_<driver>_register implementations. The + * data structure passed will be taken over by the + * console framework and *MUST* be allocated in + * persistent memory (e.g. the data section). + * In : x0 - address of console_t structure + * Out: x0 - Always 1 (for easier tail calling) + * Clobber list: x0, x1, x14 + * ----------------------------------------------- + */ +func console_register +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) + adrp x1, __STACKS_START__ + add x1, x1, :lo12:__STACKS_START__ + cmp x0, x1 + b.lo not_on_stack + adrp x1, __STACKS_END__ + add x1, x1, :lo12:__STACKS_END__ + cmp x0, x1 + ASM_ASSERT(hs) +not_on_stack: +#endif /* ENABLE_ASSERTIONS */ + adrp x14, console_list + ldr x1, [x14, :lo12:console_list] /* X1 = first struct in list */ + str x0, [x14, :lo12:console_list] /* list head = new console */ + str x1, [x0, #CONSOLE_T_NEXT] /* new console next ptr = X1 */ + mov x0, #1 + ret +endfunc console_register + + /* ----------------------------------------------- + * int console_unregister(console_t *console) + * Function to find a specific console in the list + * of currently active consoles and remove it. + * In: x0 - address of console_t struct to remove + * Out: x0 - removed address, or NULL if not found + * Clobber list: x0, x1, x14 + * ----------------------------------------------- + */ +func console_unregister + adrp x14, console_list + add x14, x14, :lo12:console_list /* X14 = ptr to first struct */ + ldr x1, [x14] /* X1 = first struct */ + +unregister_loop: + cbz x1, unregister_not_found + cmp x0, x1 + b.eq unregister_found + ldr x14, [x14] /* X14 = next ptr of struct */ + ldr x1, [x14] /* X1 = next struct */ + b unregister_loop + +unregister_found: + ldr x1, [x1] /* X1 = next struct */ + str x1, [x14] /* prev->next = cur->next */ + ret + +unregister_not_found: + mov x0, #0 /* return NULL if not found */ + ret +endfunc console_unregister + + /* ----------------------------------------------- + * void console_switch_state(unsigned int new_state) + * Function to switch the current console state. + * The console state determines which of the + * registered consoles are actually used at a time. + * In : w0 - global console state to move to + * Clobber list: x0, x1 + * ----------------------------------------------- + */ +func console_switch_state + adrp x1, console_state + strb w0, [x1, :lo12:console_state] + ret +endfunc console_switch_state + + /* ----------------------------------------------- + * void console_set_scope(console_t *console, + * unsigned int scope) + * Function to update the states that a given console + * may be active in. + * In : x0 - pointer to console_t struct + * : w1 - new active state mask + * Clobber list: x0, x1, x2 + * ----------------------------------------------- + */ +func console_set_scope +#if ENABLE_ASSERTIONS + tst w1, #~CONSOLE_FLAG_SCOPE_MASK + ASM_ASSERT(eq) +#endif /* ENABLE_ASSERTIONS */ + ldr w2, [x0, #CONSOLE_T_FLAGS] + and w2, w2, #~CONSOLE_FLAG_SCOPE_MASK + orr w2, w2, w1 + str w2, [x0, #CONSOLE_T_FLAGS] + ret +endfunc console_set_scope + + /* --------------------------------------------- + * int console_putc(int c) + * Function to output a character. Calls all + * active console's putc() handlers in succession. + * In : x0 - character to be printed + * Out: x0 - printed character on success, or < 0 + if at least one console had an error + * Clobber list : x0, x1, x2, x12, x13, x14, x15 + * --------------------------------------------- + */ +func console_putc + mov x15, x30 + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + mov w12, w0 /* W12 = character to print */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + +putc_loop: + cbz x14, putc_done + adrp x1, console_state + ldrb w1, [x1, :lo12:console_state] + ldr x2, [x14, #CONSOLE_T_FLAGS] + tst w1, w2 + b.eq putc_continue + ldr x2, [x14, #CONSOLE_T_PUTC] + cbz x2, putc_continue + mov w0, w12 + mov x1, x14 + blr x2 + cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */ + ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */ + csel w13, w0, w13, lt +putc_continue: + ldr x14, [x14] /* X14 = next struct */ + b putc_loop + +putc_done: + mov w0, w13 + ret x15 +endfunc console_putc + + /* --------------------------------------------- + * int console_getc(void) + * Function to get a character from any console. + * Keeps looping through all consoles' getc() + * handlers until one of them returns a + * character, then stops iterating and returns + * that character to the caller. Will stop looping + * if all active consoles report real errors + * (other than just not having a char available). + * Out : x0 - read character, or < 0 on error + * Clobber list : x0, x1, x13, x14, x15 + * --------------------------------------------- + */ +func console_getc + mov x15, x30 +getc_try_again: + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + cbnz x14, getc_loop + mov w0, w13 /* If no consoles registered */ + ret x15 /* return immediately. */ + +getc_loop: + adrp x0, console_state + ldrb w0, [x0, :lo12:console_state] + ldr x1, [x14, #CONSOLE_T_FLAGS] + tst w0, w1 + b.eq getc_continue + ldr x1, [x14, #CONSOLE_T_GETC] + cbz x1, getc_continue + mov x0, x14 + blr x1 + cmp w0, #0 /* if X0 >= 0: return */ + b.ge getc_found + cmp w13, #ERROR_NO_PENDING_CHAR /* may update W13 (NOCHAR has */ + csel w13, w13, w0, eq /* precedence vs real errors) */ +getc_continue: + ldr x14, [x14] /* X14 = next struct */ + cbnz x14, getc_loop + cmp w13, #ERROR_NO_PENDING_CHAR /* Keep scanning if at least */ + b.eq getc_try_again /* one console returns NOCHAR */ + mov w0, w13 + +getc_found: + ret x15 +endfunc console_getc + + /* --------------------------------------------- + * int console_flush(void) + * Function to force a write of all buffered + * data that hasn't been output. Calls all + * console's flush() handlers in succession. + * Out: x0 - 0 on success, < 0 if at least one error + * Clobber list : x0, x1, x2, x3, x4, x5, x13, x14, x15 + * --------------------------------------------- + */ +func console_flush + mov x15, x30 + mov w13, #ERROR_NO_VALID_CONSOLE /* W13 = current return value */ + adrp x14, console_list + ldr x14, [x14, :lo12:console_list] /* X14 = first console struct */ + +flush_loop: + cbz x14, flush_done + adrp x1, console_state + ldrb w1, [x1, :lo12:console_state] + ldr x2, [x14, #CONSOLE_T_FLAGS] + tst w1, w2 + b.eq flush_continue + ldr x1, [x14, #CONSOLE_T_FLUSH] + cbz x1, flush_continue + mov x0, x14 + blr x1 + cmp w13, #ERROR_NO_VALID_CONSOLE /* update W13 if it's NOVALID */ + ccmp w0, #0, #0x8, ne /* else update it if W0 < 0 */ + csel w13, w0, w13, lt +flush_continue: + ldr x14, [x14] /* X14 = next struct */ + b flush_loop + +flush_done: + mov w0, w13 + ret x15 +endfunc console_flush diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S index 9db6157d..1b5d7393 100644 --- a/drivers/console/aarch64/skeleton_console.S +++ b/drivers/console/aarch64/skeleton_console.S @@ -4,99 +4,171 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include <asm_macros.S> +#include <console_macros.S> /* - * This file contains a skeleton console implementation that can - * be used as basis for a real console implementation by platforms - * that do not contain PL011 hardware. + * This file contains a skeleton console driver that can be used as + * basis for a real console driver. Console drivers in Trusted Firmware + * can be instantiated multiple times. Each instance is described by a + * separate console_t structure which must be registered with the common + * console framework via console_register(). Console drivers should + * define a console_xxx_register() function that initializes a new + * console_t structure passed in from the caller and registers it after + * initializing the console hardware. Drivers may define their own + * structures extending console_t to store private driver information. + * Console drivers *MUST* take care that the console callbacks they + * implement only change registers allowed in the clobber lists defined + * in this file. (Note that in addition to the explicit clobber lists, + * any function may always clobber the intra-procedure-call registers + * X16 and X17, but may never depend on them retaining their values + * across any function call.) + * Platforms using drivers based on this template need to enable + * MULTI_CONSOLE_API := 1 in their platform.mk. */ - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + .globl console_xxx_register + .globl console_xxx_putc + .globl console_xxx_getc + .globl console_xxx_flush /* ----------------------------------------------- - * int console_core_init(uintptr_t 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 else 0 on error - * Clobber list : x1, x2 + * int console_xxx_register(console_xxx_t *console, + * ...additional parameters as desired...) + * Function to initialize and register the console. + * The caller needs to pass an empty console_xxx_t + * structure in which *MUST* be allocated in + * persistent memory (e.g. a global or static local + * variable, *NOT* on the stack). + * In : x0 - pointer to empty console_t structure + * x1 through x7: additional parameters as desired + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7 * ----------------------------------------------- */ -func console_core_init - /* Check the input base address */ - cbz x0, core_init_fail - /* Check baud rate and uart clock for sanity */ - cbz w1, core_init_fail - cbz w2, core_init_fail - /* Insert implementation here */ - mov w0, #1 - ret -core_init_fail: - mov w0, wzr +func console_xxx_register + /* + * Store parameters (e.g. hardware base address) in driver-specific + * console_xxx_t structure field if they will need to be retrieved + * by later console callback (e.g. putc). + * Example: + */ + str x1, [x0, #CONSOLE_T_XXX_BASE] + str x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE] + + /* + * Initialize console hardware, using x1 - x7 parameters as needed. + * Keep console_t pointer in x0 for later. + */ + + /* Macro to finish up registration and return (needs valid x0 + x30). */ + finish_console_register xxx + + /* Jump here if hardware init fails or parameters are invalid. */ +register_fail: + mov w0, #0 ret -endfunc console_core_init +endfunc console_xxx_register /* -------------------------------------------------------- - * int console_core_putc(int c, uintptr_t base_addr) + * int console_xxx_putc(int c, console_xxx_t *console) * 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 + * x1 - pointer to console_t struct + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0, x1, x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error - /* Insert implementation here */ +func console_xxx_putc + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x1. + * Example: + */ + ldr x1, [x1, #CONSOLE_T_XXX_BASE] + + /* + * Write w0 to hardware. + */ + ret + + /* Jump here if output fails for any reason. */ putc_error: mov w0, #-1 ret -endfunc console_core_putc +endfunc console_xxx_putc /* --------------------------------------------- - * int console_core_getc(uintptr_t base_addr) + * int console_xxx_getc(console_xxx_t *console) * Function to get a character from the console. - * It returns the character grabbed on success - * or -1 on error. - * In : x0 - console base address + * Even though console_getc() is blocking, this + * callback has to be non-blocking and always + * return immediately to allow polling multiple + * drivers concurrently. + * Returns the character grabbed on success, + * ERROR_NO_PENDING_CHAR if no character was + * available at this time, or any value + * between -2 and -127 if there was an error. + * In : x0 - pointer to console_t struct + * Out: w0 - character on success, + * ERROR_NO_PENDING_CHAR if no char, + * < -1 on error * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc - cbz x0, getc_error - /* Insert implementation here */ +func console_xxx_getc + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x0. + * Example: + */ + ldr x1, [x0, #CONSOLE_T_XXX_BASE] + + /* + * Try to read character into w0 from hardware. + */ + ret + + /* Jump here if there is no character available at this time. */ +getc_no_char: + mov w0, #ERROR_NO_PENDING_CHAR + ret + + /* Jump here if there was any hardware error. */ getc_error: - mov w0, #-1 + mov w0, #-2 /* may pick error codes between -2 and -127 */ ret -endfunc console_core_getc +endfunc console_xxx_getc /* --------------------------------------------- - * int console_core_flush(uintptr_t base_addr) + * int console_xxx_flush(console_xxx_t *console) * Function to force a write of all buffered * data that hasn't been output. - * In : x0 - console base address - * Out : return -1 on error else return 0. - * Clobber list : x0, x1 + * In : x0 - pointer to console_xxx_t struct + * Out: w0 - 0 on success, < 0 on error + * Clobber list : x0, x1, x2, x3, x4, x5 * --------------------------------------------- */ -func console_core_flush - cbz x0, flush_error - /* Insert implementation here */ +func console_xxx_flush + /* + * Retrieve values we need (e.g. hardware base address) from + * console_xxx_t structure pointed to by x0. + * Example: + */ + ldr x1, [x0, #CONSOLE_T_XXX_BASE] + + /* + * Flush all remaining output from hardware FIFOs. Do not return until + * all data has been flushed or there was an unrecoverable error. + */ + mov w0, #0 ret + + /* Jump here if an unrecoverable error has been encountered. */ flush_error: mov w0, #-1 ret -endfunc console_core_flush +endfunc console_xxx_flush diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S new file mode 100644 index 00000000..2fc06033 --- /dev/null +++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <cbmem_console.h> +#include <console_macros.S> + +/* + * This driver implements access to coreboot's in-memory console + * (CBMEM console). For the original implementation, see + * <coreboot>/src/lib/cbmem_console.c. + */ + + .globl console_cbmc_register + .globl console_cbmc_putc + .globl console_cbmc_flush + + /* ----------------------------------------------- + * int console_cbmc_register(console_cbmc_t *console, + * uintptr_t base) + * Registers a new CBMEM console instance. Reads + * the size field from the buffer header structure + * and stores it in our console_cbmc_t struct, so + * that we keep the size in secure memory where we + * can trust it. A malicious EL1 could manipulate + * the console buffer (including the header), so we + * must not trust its contents after boot. + * In: x0 - CBMEM console base address + * x1 - pointer to empty console_cbmc_t struct + * Out: x0 - 1 to indicate success + * Clobber list: x0, x1, x2, x7 + * ----------------------------------------------- + */ +func console_cbmc_register + str x0, [x1, #CONSOLE_T_CBMC_BASE] + ldr w2, [x0] + str w2, [x1, #CONSOLE_T_CBMC_SIZE] + mov x0, x1 + finish_console_register cbmc +endfunc console_cbmc_register + + /* ----------------------------------------------- + * int console_cbmc_puts(int c, console_cbmc_t *console) + * Writes a character to the CBMEM console buffer, + * including overflow handling of the cursor field. + * The character must be preserved in x0. + * In: x0 - character to be stored + * x1 - pointer to console_cbmc_t struct + * Clobber list: x1, x2, x16, x17 + * ----------------------------------------------- + */ +func console_cbmc_putc + ldr w2, [x1, #CONSOLE_T_CBMC_SIZE] + ldr x1, [x1, #CONSOLE_T_CBMC_BASE] + add x1, x1, #8 /* keep address of body in x1 */ + + ldr w16, [x1, #-4] /* load cursor (one u32 before body) */ + and w17, w16, #0xf0000000 /* keep flags part in w17 */ + and w16, w16, #0x0fffffff /* keep actual cursor part in w16 */ + + cmp w16, w2 /* sanity check that cursor < size */ + b.lo putc_within_bounds + mov w0, #-1 /* cursor >= size must be malicious */ + ret /* so return error, don't write char */ + +putc_within_bounds: + strb w0, [x1, w16, uxtw] /* body[cursor] = character */ + add w16, w16, #1 /* cursor++ */ + cmp w16, w2 /* if cursor < size... */ + b.lo putc_write_back /* ...skip overflow handling */ + + mov w16, #0 /* on overflow, set cursor back to 0 */ + orr w17, w17, #(1 << 31) /* and set overflow flag */ + +putc_write_back: + orr w16, w16, w17 /* merge cursor and flags back */ + str w16, [x1, #-4] /* write back cursor to memory */ + ret +endfunc console_cbmc_putc + + /* ----------------------------------------------- + * int console_cbmc_flush(console_cbmc_t *console) + * Flushes the CBMEM console by flushing the + * console buffer from the CPU's data cache. + * In: x0 - pointer to console_cbmc_t struct + * Out: x0 - 0 for success + * Clobber list: x0, x1, x2, x3, x5 + * ----------------------------------------------- + */ +func console_cbmc_flush + mov x5, x30 + ldr x1, [x0, #CONSOLE_T_CBMC_SIZE] + ldr x0, [x0, #CONSOLE_T_CBMC_BASE] + add x1, x1, #8 /* add size of console header */ + bl clean_dcache_range /* (clobbers x2 and x3) */ + mov x0, #0 + ret x5 +endfunc console_cbmc_flush diff --git a/drivers/emmc/emmc.c b/drivers/emmc/emmc.c index bcdc82ce..92d1e872 100644 --- a/drivers/emmc/emmc.c +++ b/drivers/emmc/emmc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -353,7 +353,9 @@ void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width, (clk != 0) && ((width == EMMC_BUS_WIDTH_1) || (width == EMMC_BUS_WIDTH_4) || - (width == EMMC_BUS_WIDTH_8))); + (width == EMMC_BUS_WIDTH_8) || + (width == EMMC_BUS_WIDTH_DDR_4) || + (width == EMMC_BUS_WIDTH_DDR_8))); ops = ops_ptr; emmc_flags = flags; diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S index f9ccd577..b02209df 100644 --- a/drivers/ti/uart/aarch64/16550_console.S +++ b/drivers/ti/uart/aarch64/16550_console.S @@ -6,15 +6,24 @@ #include <arch.h> #include <asm_macros.S> +#include <assert_macros.S> +#include <console_macros.S> #include <uart_16550.h> - .globl console_core_init - .globl console_core_putc - .globl console_core_getc - .globl console_core_flush + /* + * "core" functions are low-level implementations that don't require + * writable memory and are thus safe to call in BL1 crash context. + */ + .globl console_16550_core_init + .globl console_16550_core_putc + .globl console_16550_core_getc + + .globl console_16550_putc + .globl console_16550_getc + /* ----------------------------------------------- - * int console_core_init(unsigned long base_addr, + * int console_16550_core_init(uintptr_t base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This @@ -23,11 +32,11 @@ * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate - * Out: return 1 on success + * Out: return 1 on success, 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ -func console_core_init +func console_16550_core_init /* Check the input base address */ cbz x0, init_fail /* Check baud rate and uart clock for sanity */ @@ -63,12 +72,57 @@ func console_core_init mov w3, #3 str w3, [x0, #UARTMCR] mov w0, #1 + ret init_fail: + mov w0, #0 ret -endfunc console_core_init +endfunc console_16550_core_init + +#if MULTI_CONSOLE_API + .globl console_16550_register + + /* ----------------------------------------------- + * int console_16550_register(console_16550_t *console, + uintptr_t base, uint32_t clk, uint32_t baud) + * Function to initialize and register a new 16550 + * console. Storage passed in for the console struct + * *must* be persistent (i.e. not from the stack). + * In: x0 - UART register base address + * w1 - UART clock in Hz + * w2 - Baud rate + * x3 - pointer to empty console_16550_t struct + * Out: return 1 on success, 0 on error + * Clobber list : x0, x1, x2, x6, x7, x14 + * ----------------------------------------------- + */ +func console_16550_register + mov x7, x30 + mov x6, x3 + cbz x6, register_fail + str x0, [x6, #CONSOLE_T_16550_BASE] + + bl console_16550_core_init + cbz x0, register_fail + + mov x0, x6 + mov x30, x7 + finish_console_register 16550 + +register_fail: + ret x7 +endfunc console_16550_register +#else + .globl console_core_init + .globl console_core_putc + .globl console_core_getc + .globl console_core_flush + .equ console_core_init,console_16550_core_init + .equ console_core_putc,console_16550_core_putc + .equ console_core_getc,console_16550_core_getc +#endif /* -------------------------------------------------------- - * int console_core_putc(int c, unsigned int base_addr) + * int console_16550_core_putc(int c, uintptr_t 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 @@ -77,9 +131,11 @@ endfunc console_core_init * Clobber list : x2 * -------------------------------------------------------- */ -func console_core_putc - /* Check the input parameter */ - cbz x1, putc_error +func console_16550_core_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA @@ -99,34 +155,75 @@ func console_core_putc b.ne 2b str w0, [x1, #UARTTX] ret -putc_error: - mov w0, #-1 - ret -endfunc console_core_putc +endfunc console_16550_core_putc + + /* -------------------------------------------------------- + * int console_16550_putc(int c, console_16550_t *console) + * 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 - pointer to console_t structure + * Out : return -1 on error else return character. + * Clobber list : x2 + * -------------------------------------------------------- + */ +func console_16550_putc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x1, [x1, #CONSOLE_T_16550_BASE] + b console_16550_core_putc +endfunc console_16550_putc /* --------------------------------------------- - * int console_core_getc(void) + * int console_16550_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success - * or -1 on error. - * In : w0 - console base address - * Out : return -1 on error else return character. + * or -1 on if no character is available. + * In : x0 - console base address + * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ -func console_core_getc +func console_16550_core_getc +#if ENABLE_ASSERTIONS + cmp x0, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + /* Check if the receive FIFO is empty */ 1: ldr w1, [x0, #UARTLSR] - tbz w1, #UARTLSR_RDR_BIT, 1b + tbz w1, #UARTLSR_RDR_BIT, no_char ldr w0, [x0, #UARTRX] ret -getc_error: - mov w0, #-1 +no_char: + mov w0, #ERROR_NO_PENDING_CHAR ret -endfunc console_core_getc +endfunc console_16550_core_getc + + /* --------------------------------------------- + * int console_16550_getc(console_16550_t *console) + * Function to get a character from the console. + * It returns the character grabbed on success + * or -1 on if no character is available. + * In : x0 - pointer to console_t stucture + * Out : w0 - character if available, else -1 + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func console_16550_getc +#if ENABLE_ASSERTIONS + cmp x1, #0 + ASM_ASSERT(ne) +#endif /* ENABLE_ASSERTIONS */ + ldr x0, [x0, #CONSOLE_T_16550_BASE] + b console_16550_core_getc +endfunc console_16550_getc /* --------------------------------------------- * int console_core_flush(uintptr_t base_addr) + * DEPRECATED: Not used with MULTI_CONSOLE_API! * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address diff --git a/include/common/aarch32/el3_common_macros.S b/include/common/aarch32/el3_common_macros.S index 59e99f89..d654b652 100644 --- a/include/common/aarch32/el3_common_macros.S +++ b/include/common/aarch32/el3_common_macros.S @@ -260,9 +260,9 @@ * --------------------------------------------------------------------- */ .if \_init_c_runtime -#ifdef IMAGE_BL32 +#if defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* ----------------------------------------------------------------- - * Invalidate the RW memory used by the BL32 (SP_MIN) image. This + * Invalidate the RW memory used by the image. This * includes the data and NOBITS sections. This is done to * safeguard against possible corruption of this memory by * dirty cache lines in a system cache as a result of use by @@ -273,7 +273,7 @@ ldr r1, =__RW_END__ sub r1, r1, r0 bl inv_dcache_range -#endif /* IMAGE_BL32 */ +#endif ldr r0, =__BSS_START__ ldr r1, =__BSS_SIZE__ diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S new file mode 100644 index 00000000..0ebea2c1 --- /dev/null +++ b/include/common/aarch64/console_macros.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __CONSOLE_MACROS_S__ +#define __CONSOLE_MACROS_S__ + +#include <console.h> + +/* + * This macro encapsulates the common setup that has to be done at the end of + * a console driver's register function. It will register all of the driver's + * callbacks in the console_t structure and initialize the flags field (by + * default consoles are enabled for the "boot" and "crash" states, this can be + * changed after registration with the console_set_scope() function). It ends + * with a tail call that will include return to the caller. + * REQUIRES console_t pointer in x0 and a valid return address in x30. + */ + .macro finish_console_register _driver + /* + * Add these weak definitions so we will automatically write a 0 if the + * function doesn't exist. I'd rather use .ifdef but that only works if + * the function was defined (not just declared .global) above this point + * in the file, which we can't guarantee. + */ + .weak console_\_driver\()_putc + .weak console_\_driver\()_getc + .weak console_\_driver\()_flush + + /* Don't use adrp on weak funcs! See GNU ld bugzilla issue 22589. */ + ldr x1, =console_\_driver\()_putc + str x1, [x0, #CONSOLE_T_PUTC] + ldr x1, =console_\_driver\()_getc + str x1, [x0, #CONSOLE_T_GETC] + ldr x1, =console_\_driver\()_flush + str x1, [x0, #CONSOLE_T_FLUSH] + mov x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH) + str x1, [x0, #CONSOLE_T_FLAGS] + b console_register + .endm + +#endif /* __CONSOLE_MACROS_S__ */ diff --git a/include/common/aarch64/el3_common_macros.S b/include/common/aarch64/el3_common_macros.S index defd4a24..4ebf77bb 100644 --- a/include/common/aarch64/el3_common_macros.S +++ b/include/common/aarch64/el3_common_macros.S @@ -269,7 +269,7 @@ * --------------------------------------------------------------------- */ .if \_init_c_runtime -#ifdef IMAGE_BL31 +#if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* ------------------------------------------------------------- * Invalidate the RW memory used by the BL31 image. This * includes the data and NOBITS sections. This is done to @@ -282,7 +282,7 @@ adr x1, __RW_END__ sub x1, x1, x0 bl inv_dcache_range -#endif /* IMAGE_BL31 */ +#endif ldr x0, =__BSS_START__ ldr x1, =__BSS_SIZE__ diff --git a/include/common/asm_macros_common.S b/include/common/asm_macros_common.S index 6a02e18e..ca8c1ad0 100644 --- a/include/common/asm_macros_common.S +++ b/include/common/asm_macros_common.S @@ -29,7 +29,7 @@ * debugging experience. */ .cfi_sections .debug_frame - .section .text.\_name, "ax" + .section .text.asm.\_name, "ax" .type \_name, %function .func \_name /* diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h index cd259c5e..06d75435 100644 --- a/include/drivers/arm/pl011.h +++ b/include/drivers/arm/pl011.h @@ -7,6 +7,8 @@ #ifndef __PL011_H__ #define __PL011_H__ +#include <console.h> + /* PL011 Registers */ #define UARTDR 0x000 #define UARTRSR 0x004 @@ -79,4 +81,26 @@ #endif /* !PL011_GENERIC_UART */ +#define CONSOLE_T_PL011_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include <types.h> + +typedef struct { + console_t console; + uintptr_t base; +} console_pl011_t; + +/* + * Initialize a new PL011 console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_pl011_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, + console_pl011_t *console); + +#endif /*__ASSEMBLY__*/ + #endif /* __PL011_H__ */ diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h index 3aadde32..7ab6df04 100644 --- a/include/drivers/cadence/cdns_uart.h +++ b/include/drivers/cadence/cdns_uart.h @@ -7,6 +7,8 @@ #ifndef __CADENCE_UART_H__ #define __CADENCE_UART_H__ +#include <console.h> + /* This is very minimalistic and will only work in QEMU. */ /* CADENCE Registers */ @@ -23,4 +25,26 @@ #define R_UART_TX 0x30 #define R_UART_RX 0x30 +#define CONSOLE_T_CDNS_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include <types.h> + +typedef struct { + console_t console; + uintptr_t base; +} console_cdns_t; + +/* + * Initialize a new Cadence console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_cdns_register(uint64_t baseaddr, uint32_t clock, uint32_t baud, + console_cdns_t *console); + +#endif /*__ASSEMBLY__*/ + #endif diff --git a/include/drivers/console.h b/include/drivers/console.h index da5cb8f7..0629f571 100644 --- a/include/drivers/console.h +++ b/include/drivers/console.h @@ -7,14 +7,69 @@ #ifndef __CONSOLE_H__ #define __CONSOLE_H__ -#include <stdint.h> +#include <utils_def.h> -int console_init(uintptr_t base_addr, - unsigned int uart_clk, unsigned int baud_rate); -void console_uninit(void); +#define CONSOLE_T_NEXT (U(0) * REGSZ) +#define CONSOLE_T_FLAGS (U(1) * REGSZ) +#define CONSOLE_T_PUTC (U(2) * REGSZ) +#define CONSOLE_T_GETC (U(3) * REGSZ) +#define CONSOLE_T_FLUSH (U(4) * REGSZ) +#define CONSOLE_T_DRVDATA (U(5) * REGSZ) + +#define CONSOLE_FLAG_BOOT BIT(0) +#define CONSOLE_FLAG_RUNTIME BIT(1) +#define CONSOLE_FLAG_CRASH BIT(2) +/* Bits 3 to 7 reserved for additional scopes in future expansion. */ +#define CONSOLE_FLAG_SCOPE_MASK ((U(1) << 8) - 1) +/* Bits 8 to 31 reserved for non-scope use in future expansion. */ + +/* Returned by getc callbacks when receive FIFO is empty. */ +#define ERROR_NO_PENDING_CHAR (-1) +/* Returned by console_xxx() if no registered console implements xxx. */ +#define ERROR_NO_VALID_CONSOLE (-128) + +#ifndef __ASSEMBLY__ + +#include <types.h> + +typedef struct console { + struct console *next; + u_register_t flags; + int (*putc)(int character, struct console *console); + int (*getc)(struct console *console); + int (*flush)(struct console *console); + /* Additional private driver data may follow here. */ +} console_t; +#include <console_assertions.h> /* offset macro assertions for console_t */ + +/* + * NOTE: There is no publicly accessible console_register() function. Consoles + * are registered by directly calling the register function of a specific + * implementation, e.g. console_16550_register() from <uart_16550.h>. Consoles + * registered that way can be unregistered/reconfigured with below functions. + */ +/* Remove a single console_t instance from the console list. */ +int console_unregister(console_t *console); +/* Set scope mask of a console that determines in what states it is active. */ +void console_set_scope(console_t *console, unsigned int scope); + +/* Switch to a new global console state (CONSOLE_FLAG_BOOT/RUNTIME/CRASH). */ +void console_switch_state(unsigned int new_state); +/* Output a character on all consoles registered for the current state. */ int console_putc(int c); +/* Read a character (blocking) from any console registered for current state. */ int console_getc(void); +/* Flush all consoles registered for the current state. */ int console_flush(void); +#if !MULTI_CONSOLE_API +/* DEPRECATED on AArch64 -- use console_<driver>_register() instead! */ +int console_init(uintptr_t base_addr, + unsigned int uart_clk, unsigned int baud_rate) __deprecated; +void console_uninit(void) __deprecated; +#endif + +#endif /* __ASSEMBLY__ */ + #endif /* __CONSOLE_H__ */ diff --git a/include/drivers/console_assertions.h b/include/drivers/console_assertions.h new file mode 100644 index 00000000..cedce867 --- /dev/null +++ b/include/drivers/console_assertions.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __CONSOLE_ASSERTIONS_H__ +#define __CONSOLE_ASSERTIONS_H__ + +#include <cassert.h> + +/* + * This file contains some separate assertions about console_t, moved here to + * keep them out of the way. Should only be included from <console.h>. + */ +CASSERT(CONSOLE_T_NEXT == __builtin_offsetof(console_t, next), + assert_console_t_next_offset_mismatch); +CASSERT(CONSOLE_T_FLAGS == __builtin_offsetof(console_t, flags), + assert_console_t_flags_offset_mismatch); +CASSERT(CONSOLE_T_PUTC == __builtin_offsetof(console_t, putc), + assert_console_t_putc_offset_mismatch); +CASSERT(CONSOLE_T_GETC == __builtin_offsetof(console_t, getc), + assert_console_t_getc_offset_mismatch); +CASSERT(CONSOLE_T_FLUSH == __builtin_offsetof(console_t, flush), + assert_console_t_flush_offset_mismatch); +CASSERT(CONSOLE_T_DRVDATA == sizeof(console_t), + assert_console_t_drvdata_offset_mismatch); + +#endif /* __CONSOLE_ASSERTIONS_H__ */ + diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h new file mode 100644 index 00000000..4fca36f6 --- /dev/null +++ b/include/drivers/coreboot/cbmem_console.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __CBMEM_CONSOLE_H__ +#define __CBMEM_CONSOLE_H__ + +#include <console.h> + +#define CONSOLE_T_CBMC_BASE CONSOLE_T_DRVDATA +#define CONSOLE_T_CBMC_SIZE (CONSOLE_T_DRVDATA + REGSZ) + +#ifndef __ASSEMBLER__ + +typedef struct { + console_t console; + uintptr_t base; + uint32_t size; +} console_cbmc_t; + +int console_cbmc_register(uintptr_t base, console_cbmc_t *console); + +#endif /* __ASSEMBLER__ */ + +#endif /* __CBMEM_CONSOLE_H__ */ diff --git a/include/drivers/emmc.h b/include/drivers/emmc.h index 921f4cfe..286c014a 100644 --- a/include/drivers/emmc.h +++ b/include/drivers/emmc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -25,6 +25,7 @@ #define EMMC_CMD13 13 #define EMMC_CMD17 17 #define EMMC_CMD18 18 +#define EMMC_CMD21 21 #define EMMC_CMD23 23 #define EMMC_CMD24 24 #define EMMC_CMD25 25 @@ -61,6 +62,8 @@ #define EMMC_BUS_WIDTH_1 0 #define EMMC_BUS_WIDTH_4 1 #define EMMC_BUS_WIDTH_8 2 +#define EMMC_BUS_WIDTH_DDR_4 5 +#define EMMC_BUS_WIDTH_DDR_8 6 #define EMMC_BOOT_MODE_BACKWARD (0 << 3) #define EMMC_BOOT_MODE_HS_TIMING (1 << 3) #define EMMC_BOOT_MODE_DDR (2 << 3) diff --git a/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h index f258d45b..9eba41aa 100644 --- a/include/drivers/ti/uart/uart_16550.h +++ b/include/drivers/ti/uart/uart_16550.h @@ -7,6 +7,8 @@ #ifndef __UART_16550_H__ #define __UART_16550_H__ +#include <console.h> + /* UART16550 Registers */ #define UARTTX 0x0 #define UARTRX 0x0 @@ -67,4 +69,26 @@ #define UARTLSR_RDR_BIT (0) /* Rx Data Ready Bit */ #define UARTLSR_RDR (1 << UARTLSR_RDR_BIT) /* Rx Data Ready */ +#define CONSOLE_T_16550_BASE CONSOLE_T_DRVDATA + +#ifndef __ASSEMBLY__ + +#include <types.h> + +typedef struct { + console_t console; + uintptr_t base; +} console_16550_t; + +/* + * Initialize a new 16550 console instance and register it with the console + * framework. The |console| pointer must point to storage that will be valid + * for the lifetime of the console, such as a global or static local variable. + * Its contents will be reinitialized from scratch. + */ +int console_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, + console_16550_t *console); + +#endif /*__ASSEMBLY__*/ + #endif /* __UART_16550_H__ */ diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h new file mode 100644 index 00000000..4b1f200a --- /dev/null +++ b/include/lib/coreboot.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __COREBOOT_H__ +#define __COREBOOT_H__ + +#include <types.h> + +typedef struct { + uint32_t type; /* always 2 (memory-mapped) on ARM */ + uint32_t baseaddr; + uint32_t baud; + uint32_t regwidth; /* in bytes, i.e. usually 4 */ + uint32_t input_hertz; + uint32_t uart_pci_addr; /* unused on current ARM systems */ +} coreboot_serial_t; +extern coreboot_serial_t coreboot_serial; + +void coreboot_table_setup(void *base); + +#endif /* __COREBOOT_H__ */ diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S index e2e4316d..0f3a5728 100644 --- a/include/lib/cpus/aarch32/cpu_macros.S +++ b/include/lib/cpus/aarch32/cpu_macros.S @@ -9,6 +9,10 @@ #include <arch.h> #include <errata_report.h> +#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) +#define IMAGE_AT_EL3 +#endif + #define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \ (MIDR_PN_MASK << MIDR_PN_SHIFT) @@ -38,7 +42,7 @@ CPU_MIDR: /* cpu_ops midr */ .space 4 /* Reset fn is needed during reset */ -#if defined(IMAGE_BL1) || defined(IMAGE_BL32) +#if defined(IMAGE_AT_EL3) CPU_RESET_FUNC: /* cpu_ops reset_func */ .space 4 #endif @@ -54,7 +58,7 @@ CPU_PWR_DWN_OPS: /* cpu_ops power down functions */ #if REPORT_ERRATA CPU_ERRATA_FUNC: /* CPU errata status printing function */ .space 4 -#ifdef IMAGE_BL32 +#if defined(IMAGE_BL32) CPU_ERRATA_LOCK: .space 4 CPU_ERRATA_PRINTED: @@ -120,7 +124,7 @@ CPU_OPS_SIZE = . .align 2 .type cpu_ops_\_name, %object .word \_midr -#if defined(IMAGE_BL1) || defined(IMAGE_BL32) +#if defined(IMAGE_AT_EL3) .word \_resetfunc #endif #ifdef IMAGE_BL32 diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S index a8c23e5e..ccf53066 100644 --- a/include/lib/cpus/aarch64/cpu_macros.S +++ b/include/lib/cpus/aarch64/cpu_macros.S @@ -21,6 +21,10 @@ /* Word size for 64-bit CPUs */ #define CPU_WORD_SIZE 8 +#if defined(IMAGE_BL1) || defined(IMAGE_BL31) ||(defined(IMAGE_BL2) && BL2_AT_EL3) +#define IMAGE_AT_EL3 +#endif + /* * Whether errata status needs reporting. Errata status is printed in debug * builds for both BL1 and BL31 images. @@ -38,7 +42,7 @@ CPU_MIDR: /* cpu_ops midr */ .space 8 /* Reset fn is needed in BL at reset vector */ -#if defined(IMAGE_BL1) || defined(IMAGE_BL31) +#if defined(IMAGE_AT_EL3) CPU_RESET_FUNC: /* cpu_ops reset_func */ .space 8 #endif @@ -54,7 +58,7 @@ CPU_PWR_DWN_OPS: /* cpu_ops power down functions */ #if REPORT_ERRATA CPU_ERRATA_FUNC: .space 8 -#ifdef IMAGE_BL31 +#if defined(IMAGE_BL31) CPU_ERRATA_LOCK: .space 8 CPU_ERRATA_PRINTED: @@ -124,7 +128,7 @@ CPU_OPS_SIZE = . .align 3 .type cpu_ops_\_name, %object .quad \_midr -#if defined(IMAGE_BL1) || defined(IMAGE_BL31) +#if defined(IMAGE_AT_EL3) .quad \_resetfunc #endif #ifdef IMAGE_BL31 diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h index 185a1c12..bda3b073 100644 --- a/include/lib/utils_def.h +++ b/include/lib/utils_def.h @@ -16,7 +16,7 @@ #define SIZE_FROM_LOG2_WORDS(n) (4 << (n)) -#define BIT(nr) (1ULL << (nr)) +#define BIT(nr) (ULL(1) << (nr)) /* * This variant of div_round_up can be used in macro definition but should not @@ -84,6 +84,13 @@ # define ULL(_x) (_x##ull) #endif +/* Register size of the current architecture. */ +#ifdef AARCH32 +#define REGSZ U(4) +#else +#define REGSZ U(8) +#endif + /* * Test for the current architecture version to be at least the version * expected. diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h index 1be99b71..de1c2d4b 100644 --- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h +++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h @@ -168,7 +168,7 @@ struct xlat_ctx { * This IMAGE_EL macro must not to be used outside the library, and it is only * used in AArch64. */ -#if defined(IMAGE_BL1) || defined(IMAGE_BL31) +#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) # define IMAGE_EL 3 # define IMAGE_XLAT_DEFAULT_REGIME EL3_REGIME #else diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h index f38c357b..697a0b04 100644 --- a/include/plat/arm/common/arm_def.h +++ b/include/plat/arm/common/arm_def.h @@ -334,6 +334,11 @@ #define BL2_BASE (BL1_RW_BASE - PLAT_ARM_MAX_BL2_SIZE) #define BL2_LIMIT BL1_RW_BASE +#elif BL2_AT_EL3 + +#define BL2_BASE ARM_BL_RAM_BASE +#define BL2_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) + #elif defined(AARCH32) || JUNO_AARCH32_EL3_RUNTIME /* * Put BL2 just below BL32. diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index abd73953..dfd7a204 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -145,6 +145,10 @@ uint32_t arm_get_spsr_for_bl32_entry(void); uint32_t arm_get_spsr_for_bl33_entry(void); int arm_bl2_handle_post_image_load(unsigned int image_id); +/* BL2 at EL3 functions */ +void arm_bl2_el3_early_platform_setup(void); +void arm_bl2_el3_plat_arch_setup(void); + /* BL2U utility functions */ void arm_bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info); diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index f11bee9f..09601058 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -235,6 +235,21 @@ void bl2_plat_get_bl32_meminfo(struct meminfo *mem_info); * Optional BL2 functions (may be overridden) ******************************************************************************/ + +/******************************************************************************* + * Mandatory BL2 at EL3 functions: Must be implemented if BL2_AT_EL3 image is + * supported + ******************************************************************************/ +void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3); +void bl2_el3_plat_arch_setup(void); + + +/******************************************************************************* + * Optional BL2 at EL3 functions (may be overridden) + ******************************************************************************/ +void bl2_el3_plat_prepare_exit(void); + /******************************************************************************* * Mandatory BL2U functions. ******************************************************************************/ diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk new file mode 100644 index 00000000..bbaa3329 --- /dev/null +++ b/lib/coreboot/coreboot.mk @@ -0,0 +1,24 @@ +# +# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +COREBOOT := 0 +$(eval $(call assert_boolean,COREBOOT)) +$(eval $(call add_define,COREBOOT)) + +ifeq (${COREBOOT},1) + +ifneq (${ARCH},aarch64) +$(error "coreboot only supports Trusted Firmware on AArch64.") +endif + +BL31_SOURCES += $(addprefix lib/coreboot/, \ + coreboot_table.c) + +BL31_SOURCES += drivers/coreboot/cbmem_console/${ARCH}/cbmem_console.S + +INCLUDES += -Iinclude/drivers/coreboot + +endif # COREBOOT diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c new file mode 100644 index 00000000..64f8879e --- /dev/null +++ b/lib/coreboot/coreboot_table.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <cbmem_console.h> +#include <coreboot.h> +#include <debug.h> +#include <mmio.h> +#include <string.h> +#include <xlat_tables_v2.h> + +/* + * Structures describing coreboot's in-memory descriptor tables. See + * <coreboot>/src/commonlib/include/commonlib/coreboot_tables.h for + * canonical implementation. + */ + +typedef struct { + char signature[4]; + uint32_t header_bytes; + uint32_t header_checksum; + uint32_t table_bytes; + uint32_t table_checksum; + uint32_t table_entries; +} cb_header_t; + +typedef enum { + CB_TAG_SERIAL = 0xf, + CB_TAG_CBMEM_CONSOLE = 0x17, +} cb_tag_t; + +typedef struct { + uint32_t tag; + uint32_t size; + union { + coreboot_serial_t serial; + uint64_t uint64; + }; +} cb_entry_t; + +coreboot_serial_t coreboot_serial; + +/* + * The coreboot table is parsed before the MMU is enabled (i.e. with strongly + * ordered memory), so we cannot make unaligned accesses. The table entries + * immediately follow one another without padding, so nothing after the header + * is guaranteed to be naturally aligned. Therefore, we need to define safety + * functions that can read unaligned integers. + */ +static uint32_t read_le32(uint32_t *p) +{ + uintptr_t addr = (uintptr_t)p; + return mmio_read_8(addr) | + mmio_read_8(addr + 1) << 8 | + mmio_read_8(addr + 2) << 16 | + mmio_read_8(addr + 3) << 24; +} +static uint64_t read_le64(uint64_t *p) +{ + return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32; +} + +static void expand_and_mmap(uintptr_t baseaddr, size_t size) +{ + uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE); + size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE); + mmap_add_region(pageaddr, pageaddr, expanded, + MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER); +} + +static void setup_cbmem_console(uintptr_t baseaddr) +{ + static console_cbmc_t console; + assert(!console.base); /* should only have one CBMEM console */ + + /* CBMEM console structure stores its size in first header field. */ + uint32_t size = *(uint32_t *)baseaddr; + expand_and_mmap(baseaddr, size); + console_cbmc_register(baseaddr, &console); + console_set_scope(&console.console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | + CONSOLE_FLAG_CRASH); +} + +void coreboot_table_setup(void *base) +{ + cb_header_t *header = base; + void *ptr; + int i; + + if (strncmp(header->signature, "LBIO", 4)) { + ERROR("coreboot table signature corrupt!\n"); + return; + } + + ptr = base + header->header_bytes; + for (i = 0; i < header->table_entries; i++) { + cb_entry_t *entry = ptr; + + if (ptr - base >= header->header_bytes + header->table_bytes) { + ERROR("coreboot table exceeds its bounds!\n"); + break; + } + + switch (read_le32(&entry->tag)) { + case CB_TAG_SERIAL: + memcpy(&coreboot_serial, &entry->serial, + sizeof(coreboot_serial)); + break; + case CB_TAG_CBMEM_CONSOLE: + setup_cbmem_console(read_le64(&entry->uint64)); + break; + default: + /* There are many tags TF doesn't need to care about. */ + break; + } + + ptr += read_le32(&entry->size); + } +} diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S index 75505206..35b9bc2e 100644 --- a/lib/cpus/aarch32/cortex_a72.S +++ b/lib/cpus/aarch32/cortex_a72.S @@ -109,7 +109,7 @@ func cortex_a72_reset_func orr64_imm r0, r1, CORTEX_A72_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A72_ECTLR isb - bx lr + bx r5 endfunc cortex_a72_reset_func /* ---------------------------------------------------- diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S index bfdc1e4f..72e42c67 100644 --- a/lib/cpus/aarch32/cpu_helpers.S +++ b/lib/cpus/aarch32/cpu_helpers.S @@ -10,7 +10,7 @@ #include <cpu_data.h> #include <cpu_macros.S> -#if defined(IMAGE_BL1) || defined(IMAGE_BL32) +#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler @@ -42,7 +42,7 @@ func reset_handler bx lr endfunc reset_handler -#endif /* IMAGE_BL1 || IMAGE_BL32 */ +#endif #ifdef IMAGE_BL32 /* The power down core and cluster is needed only in BL32 */ /* diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S index 23845534..ae1c3c25 100644 --- a/lib/cpus/aarch64/cpu_helpers.S +++ b/lib/cpus/aarch64/cpu_helpers.S @@ -7,7 +7,7 @@ #include <arch.h> #include <asm_macros.S> #include <assert_macros.S> -#ifdef IMAGE_BL31 +#if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) #include <cpu_data.h> #endif #include <cpu_macros.S> @@ -15,7 +15,7 @@ #include <errata_report.h> /* Reset fn is needed in BL at reset vector */ -#if defined(IMAGE_BL1) || defined(IMAGE_BL31) +#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler @@ -47,7 +47,7 @@ func reset_handler ret endfunc reset_handler -#endif /* IMAGE_BL1 || IMAGE_BL31 */ +#endif #ifdef IMAGE_BL31 /* The power down core and cluster is needed only in BL31 */ /* diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c index 8d9f704a..182679d1 100644 --- a/lib/cpus/errata_report.c +++ b/lib/cpus/errata_report.c @@ -20,6 +20,8 @@ # define BL_STRING "BL31" #elif defined(AARCH32) && defined(IMAGE_BL32) # define BL_STRING "BL32" +#elif defined(IMAGE_BL2) && BL2_AT_EL3 +# define BL_STRING "BL2" #else # error This image should not be printing errata status #endif diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index fa0d17de..a80a4915 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -27,10 +27,17 @@ ARM_GIC_ARCH := 2 # Base commit to perform code check on BASE_COMMIT := origin/master +# Execute BL2 at EL3 +BL2_AT_EL3 := 0 + # By default, consider that the platform may release several CPUs out of reset. # The platform Makefile is free to override this value. COLD_BOOT_SINGLE_CPU := 0 +# Flag to compile in coreboot support code. Exclude by default. The coreboot +# Makefile system will set this when compiling TF as part of a coreboot image. +COREBOOT := 0 + # For Chain of Trust CREATE_KEYS := 1 @@ -91,6 +98,10 @@ KEY_ALG := rsa # Flag to enable new version of image loading LOAD_IMAGE_V2 := 0 +# Use the new console API that allows registering more than one console instance +# at once. Use = instead of := to dynamically default to ERROR_DEPRECATED. +MULTI_CONSOLE_API = $(ERROR_DEPRECATED) + # NS timer register save and restore NS_TIMER_SWITCH := 0 diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk index 6e6e2739..cda8d726 100644 --- a/make_helpers/tbbr/tbbr_tools.mk +++ b/make_helpers/tbbr/tbbr_tools.mk @@ -64,7 +64,9 @@ $(if ${NON_TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${NON_TRUSTED_WORLD $(if ${BL2},$(eval $(call CERT_ADD_CMD_OPT,${BL2},--tb-fw,true)),\ $(eval $(call CERT_ADD_CMD_OPT,$(call IMG_BIN,2),--tb-fw,true))) $(eval $(call CERT_ADD_CMD_OPT,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) +ifeq (${BL2_AT_EL3}, 0) $(eval $(call FIP_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) +endif # Add the SCP_BL2 CoT (key cert + img cert + image) ifneq (${SCP_BL2},) diff --git a/plat/arm/board/fvp/fvp_bl2_el3_setup.c b/plat/arm/board/fvp/fvp_bl2_el3_setup.c new file mode 100644 index 00000000..69f2f7ad --- /dev/null +++ b/plat/arm/board/fvp/fvp_bl2_el3_setup.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <plat_arm.h> +#include "fvp_private.h" + +void bl2_el3_early_platform_setup(u_register_t arg0 __unused, + u_register_t arg1 __unused, + u_register_t arg2 __unused, + u_register_t arg3 __unused) +{ + arm_bl2_el3_early_platform_setup(); + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); + + /* + * Initialize Interconnect for this cluster during cold boot. + * No need for locks as no other CPU is active. + */ + fvp_interconnect_init(); + /* + * Enable coherency in Interconnect for the primary CPU's cluster. + */ + fvp_interconnect_enable(); +} diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 9d3c5f6b..a257784c 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -126,6 +126,13 @@ BL2_SOURCES += drivers/io/io_semihosting.c \ plat/arm/board/fvp/fvp_trusted_boot.c \ ${FVP_SECURITY_SOURCES} +ifeq (${BL2_AT_EL3},1) +BL2_SOURCES += plat/arm/board/fvp/${ARCH}/fvp_helpers.S \ + plat/arm/board/fvp/fvp_bl2_el3_setup.c \ + ${FVP_CPU_LIBS} \ + ${FVP_INTERCONNECT_SOURCES} +endif + ifeq (${FVP_USE_SP804_TIMER},1) BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c endif @@ -165,5 +172,9 @@ endif # Add support for platform supplied linker script for BL31 build $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) +ifneq (${BL2_AT_EL3}, 0) + override BL1_SOURCES = +endif + include plat/arm/board/common/board_common.mk include plat/arm/common/arm_common.mk diff --git a/plat/arm/common/arm_bl2_el3_setup.c b/plat/arm/common/arm_bl2_el3_setup.c new file mode 100644 index 00000000..e70d115e --- /dev/null +++ b/plat/arm/common/arm_bl2_el3_setup.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <console.h> +#include <generic_delay_timer.h> +#include <plat_arm.h> +#include <platform.h> + +#pragma weak bl2_el3_early_platform_setup +#pragma weak bl2_el3_plat_arch_setup +#pragma weak bl2_el3_plat_prepare_exit + +static meminfo_t bl2_el3_tzram_layout; + +/* + * Perform arm specific early platform setup. At this moment we only initialize + * the console and the memory layout. + */ +void arm_bl2_el3_early_platform_setup(void) +{ + /* Initialize the console to provide early debug support */ + console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, + ARM_CONSOLE_BAUDRATE); + + /* + * Allow BL2 to see the whole Trusted RAM. This is determined + * statically since we cannot rely on BL1 passing this information + * in the BL2_AT_EL3 case. + */ + bl2_el3_tzram_layout.total_base = ARM_BL_RAM_BASE; + bl2_el3_tzram_layout.total_size = ARM_BL_RAM_SIZE; + + /* Initialise the IO layer and register platform IO devices */ + plat_arm_io_setup(); +} + +void bl2_el3_early_platform_setup(u_register_t arg0 __unused, + u_register_t arg1 __unused, + u_register_t arg2 __unused, + u_register_t arg3 __unused) +{ + arm_bl2_el3_early_platform_setup(); + + /* + * Initialize Interconnect for this cluster during cold boot. + * No need for locks as no other CPU is active. + */ + plat_arm_interconnect_init(); + /* + * Enable Interconnect coherency for the primary CPU's cluster. + */ + plat_arm_interconnect_enter_coherency(); + + generic_delay_timer_init(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only initializes the mmu in a quick and dirty way. + ******************************************************************************/ +void arm_bl2_el3_plat_arch_setup(void) +{ + arm_setup_page_tables(bl2_el3_tzram_layout.total_base, + bl2_el3_tzram_layout.total_size, + BL_CODE_BASE, + BL_CODE_END, + BL_RO_DATA_BASE, + BL_RO_DATA_END +#if USE_COHERENT_MEM + , BL_COHERENT_RAM_BASE, + BL_COHERENT_RAM_END +#endif + ); + +#ifdef AARCH32 + enable_mmu_secure(0); +#else + enable_mmu_el3(0); +#endif +} + +void bl2_el3_plat_arch_setup(void) +{ + arm_bl2_el3_plat_arch_setup(); +} + +void bl2_el3_plat_prepare_exit(void) +{ +} diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk index fab57f14..e6ce18a7 100644 --- a/plat/arm/common/arm_common.mk +++ b/plat/arm/common/arm_common.mk @@ -150,6 +150,11 @@ BL2_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl2_setup.c \ plat/arm/common/arm_io_storage.c + +ifeq (${BL2_AT_EL3},1) +BL2_SOURCES += plat/arm/common/arm_bl2_el3_setup.c +endif + ifeq (${LOAD_IMAGE_V2},1) # Because BL1/BL2 execute in AArch64 mode but BL32 in AArch32 we need to use # the AArch32 descriptors. diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c index a87e7c67..cfc0c4f4 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -39,11 +39,11 @@ void bl32_plat_enable_mmu(uint32_t flags) void bl31_plat_runtime_setup(void) { - /* - * Finish the use of console driver in BL31 so that any runtime logs - * from BL31 will be suppressed. - */ +#if MULTI_CONSOLE_API + console_switch_state(CONSOLE_FLAG_RUNTIME); +#else console_uninit(); +#endif } #if !ENABLE_PLAT_COMPAT diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S index 797a9363..85267527 100644 --- a/plat/common/aarch64/platform_helpers.S +++ b/plat/common/aarch64/platform_helpers.S @@ -6,6 +6,7 @@ #include <arch.h> #include <asm_macros.S> +#include <console.h> #include <platform_def.h> .weak plat_report_exception @@ -56,33 +57,78 @@ func plat_report_exception ret endfunc plat_report_exception +#if MULTI_CONSOLE_API /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. + * int plat_crash_console_init(void) + * Use normal console by default. Switch it to crash + * mode so serial consoles become active again. + * NOTE: This default implementation will only work for + * crashes that occur after a normal console (marked + * valid for the crash state) has been registered with + * the console framework. To debug crashes that occur + * earlier, the platform has to override these functions + * with an implementation that initializes a console + * driver with hardcoded parameters. See + * docs/porting-guide.rst for more information. * ----------------------------------------------------- */ func plat_crash_console_init +#if defined(IMAGE_BL1) + /* + * BL1 code can possibly crash so early that the data segment is not yet + * accessible. Don't risk undefined behavior by trying to run the normal + * console framework. Platforms that want to debug BL1 will need to + * override this with custom functions that can run from registers only. + */ mov x0, #0 ret +#else /* IMAGE_BL1 */ + mov x3, x30 + mov x0, #CONSOLE_FLAG_CRASH + bl console_switch_state + mov x0, #1 + ret x3 +#endif endfunc plat_crash_console_init /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. + * void plat_crash_console_putc(int character) + * Output through the normal console by default. * ----------------------------------------------------- */ func plat_crash_console_putc - ret + b console_putc endfunc plat_crash_console_putc /* ----------------------------------------------------- - * Placeholder function which should be redefined by - * each platform. + * void plat_crash_console_flush(void) + * Flush normal console by default. + * ----------------------------------------------------- + */ +func plat_crash_console_flush + b console_flush +endfunc plat_crash_console_flush + +#else /* MULTI_CONSOLE_API */ + + /* ----------------------------------------------------- + * In the old API these are all no-op stubs that need to + * be overridden by the platform to be useful. * ----------------------------------------------------- */ +func plat_crash_console_init + mov x0, #0 + ret +endfunc plat_crash_console_init + +func plat_crash_console_putc + ret +endfunc plat_crash_console_putc + func plat_crash_console_flush ret endfunc plat_crash_console_flush +#endif /* ----------------------------------------------------- * Placeholder function which should be redefined by diff --git a/plat/common/plat_bl2_el3_common.c b/plat/common/plat_bl2_el3_common.c new file mode 100644 index 00000000..358a02d5 --- /dev/null +++ b/plat/common/plat_bl2_el3_common.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <errno.h> +#include <platform_def.h> + +/* + * The following platform functions are weakly defined. They + * are default implementations that allow BL2 to compile in + * absence of real definitions. The Platforms may override + * with more complex definitions. + */ +#pragma weak bl2_el3_plat_prepare_exit + +void bl2_el3_plat_prepare_exit(void) +{ +} diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S index abfb5a79..f415f877 100644 --- a/plat/rockchip/common/aarch64/plat_helpers.S +++ b/plat/rockchip/common/aarch64/plat_helpers.S @@ -19,10 +19,9 @@ .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl platform_is_primary_cpu - .globl plat_crash_console_init - .globl plat_crash_console_putc .globl plat_my_core_pos .globl plat_reset_handler + .globl plat_panic_handler /* * void plat_reset_handler(void); @@ -82,30 +81,17 @@ func platform_is_primary_cpu endfunc platform_is_primary_cpu /* -------------------------------------------------------------------- - * int plat_crash_console_init(void) - * Function to initialize the crash console - * without a C Runtime to print crash report. - * Clobber list : x0, x1, x2 + * void plat_panic_handler(void) + * Call system reset function on panic. Set up an emergency stack so we + * can run C functions (it only needs to last for a few calls until we + * reboot anyway). * -------------------------------------------------------------------- */ -func plat_crash_console_init - mov_imm x0, PLAT_RK_UART_BASE - mov_imm x1, PLAT_RK_UART_CLOCK - mov_imm x2, PLAT_RK_UART_BAUDRATE - b console_core_init -endfunc plat_crash_console_init - - /* -------------------------------------------------------------------- - * int plat_crash_console_putc(void) - * Function to print a character on the crash - * console without a C Runtime. - * Clobber list : x1, x2 - * -------------------------------------------------------------------- - */ -func plat_crash_console_putc - mov_imm x1, PLAT_RK_UART_BASE - b console_core_putc -endfunc plat_crash_console_putc +func plat_panic_handler + msr spsel, #0 + bl plat_set_my_stack + b rockchip_soc_soft_reset +endfunc plat_panic_handler /* -------------------------------------------------------------------- * void platform_cpu_warmboot (void); diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c index 292f0dd7..6199edae 100644 --- a/plat/rockchip/common/bl31_plat_setup.c +++ b/plat/rockchip/common/bl31_plat_setup.c @@ -8,12 +8,14 @@ #include <assert.h> #include <bl_common.h> #include <console.h> +#include <coreboot.h> #include <debug.h> #include <generic_delay_timer.h> #include <mmio.h> #include <plat_private.h> #include <platform.h> #include <platform_def.h> +#include <uart_16550.h> /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout @@ -69,8 +71,20 @@ void params_early_setup(void *plat_param_from_bl2) void bl31_early_platform_setup(bl31_params_t *from_bl2, void *plat_params_from_bl2) { - console_init(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, - PLAT_RK_UART_BAUDRATE); + static console_16550_t console; + + params_early_setup(plat_params_from_bl2); + +#if COREBOOT + if (coreboot_serial.type) + console_16550_register(coreboot_serial.baseaddr, + coreboot_serial.input_hertz, + coreboot_serial.baud, + &console); +#else + console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK, + PLAT_RK_UART_BAUDRATE, &console); +#endif VERBOSE("bl31_setup\n"); @@ -82,9 +96,6 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, bl32_ep_info = *from_bl2->bl32_ep_info; bl33_ep_info = *from_bl2->bl33_ep_info; - - /* there may have some board sepcific message need to initialize */ - params_early_setup(plat_params_from_bl2); } /******************************************************************************* diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S index be1a9fa5..6b3cb6a7 100644 --- a/plat/rockchip/common/include/plat_macros.S +++ b/plat/rockchip/common/include/plat_macros.S @@ -38,14 +38,14 @@ cci_iface_regs: * The below utility macro prints out relevant GIC * and CCI registers whenever an unhandled * exception is taken in BL31. - * Expects: GICD base in x16, GICC base in x17 + * Expects: GICD base in x26, GICC base in x27 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro plat_crash_print_regs - mov_imm x16, PLAT_RK_GICD_BASE - mov_imm x17, PLAT_RK_GICC_BASE + mov_imm x26, PLAT_RK_GICD_BASE + mov_imm x27, PLAT_RK_GICC_BASE /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 @@ -72,19 +72,19 @@ print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ - ldr w8, [x17, #GICC_HPPIR] - ldr w9, [x17, #GICC_AHPPIR] - ldr w10, [x17, #GICC_CTLR] + ldr w8, [x27, #GICC_HPPIR] + ldr w9, [x27, #GICC_AHPPIR] + ldr w10, [x27, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ - add x7, x16, #GICD_ISPENDR + add x7, x26, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: - sub x4, x7, x16 + sub x4, x7, x26 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h index aa13f878..71099076 100644 --- a/plat/rockchip/common/include/plat_params.h +++ b/plat/rockchip/common/include/plat_params.h @@ -56,6 +56,7 @@ enum { PARAM_POWEROFF, PARAM_SUSPEND_GPIO, PARAM_SUSPEND_APIO, + PARAM_COREBOOT_TABLE, }; struct apio_info { @@ -89,4 +90,9 @@ struct bl31_apio_param { struct apio_info apio; }; +struct bl31_u64_param { + struct bl31_plat_param h; + uint64_t value; +}; + #endif /* __PLAT_PARAMS_H__ */ diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c index b37acb76..65afe876 100644 --- a/plat/rockchip/common/params_setup.c +++ b/plat/rockchip/common/params_setup.c @@ -8,6 +8,7 @@ #include <assert.h> #include <bl_common.h> #include <console.h> +#include <coreboot.h> #include <debug.h> #include <gpio.h> #include <mmio.h> @@ -84,6 +85,12 @@ void params_early_setup(void *plat_param_from_bl2) sizeof(struct bl31_apio_param)); suspend_apio = ¶m_apio.apio; break; +#if COREBOOT + case PARAM_COREBOOT_TABLE: + coreboot_table_setup((void *) + ((struct bl31_u64_param *)bl2_param)->value); + break; +#endif default: ERROR("not expected type found %ld\n", bl2_param->type); diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk index 5de4680e..6e4d5b4d 100644 --- a/plat/rockchip/rk3328/platform.mk +++ b/plat/rockchip/rk3328/platform.mk @@ -49,6 +49,9 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/soc/soc.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +include lib/coreboot/coreboot.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER)) diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk index d3c6eeff..ad204e9e 100644 --- a/plat/rockchip/rk3368/platform.mk +++ b/plat/rockchip/rk3368/platform.mk @@ -49,6 +49,9 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c \ ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +include lib/coreboot/coreboot.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk index 33b9723d..9e369e48 100644 --- a/plat/rockchip/rk3399/platform.mk +++ b/plat/rockchip/rk3399/platform.mk @@ -64,6 +64,9 @@ BL31_SOURCES += ${RK_GIC_SOURCES} \ ${RK_PLAT_SOC}/drivers/dram/suspend.c ENABLE_PLAT_COMPAT := 0 +MULTI_CONSOLE_API := 1 + +include lib/coreboot/coreboot.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk index f99bbf58..e0ddfa82 100644 --- a/plat/socionext/uniphier/platform.mk +++ b/plat/socionext/uniphier/platform.mk @@ -6,7 +6,6 @@ override COLD_BOOT_SINGLE_CPU := 1 override ENABLE_PLAT_COMPAT := 0 -override ERROR_DEPRECATED := 1 override LOAD_IMAGE_V2 := 1 override USE_COHERENT_MEM := 1 override USE_TBBR_DEFS := 1 |