Merge pull request #1236 from dbasehore/gic-save-restore

RK3399 GIC save/restore
diff --git a/Makefile b/Makefile
index 1cd6b62..aa71ee3 100644
--- a/Makefile
+++ b/Makefile
@@ -127,6 +127,12 @@
 PP			:=	${CROSS_COMPILE}gcc -E
 DTC			?=	dtc
 
+# Use ${LD}.bfd instead if it exists (as absolute path or together with $PATH).
+ifneq ($(strip $(wildcard ${LD}.bfd) \
+	$(foreach dir,$(subst :, ,${PATH}),$(wildcard ${dir}/${LD}.bfd))),)
+LD			:=	${LD}.bfd
+endif
+
 ifeq (${ARM_ARCH_MAJOR},7)
 target32-directive	= 	-target arm-none-eabi
 # Will set march32-directive from platform configuration
@@ -163,7 +169,7 @@
 GCC_V_OUTPUT		:=	$(shell $(CC) -v 2>&1)
 PIE_FOUND		:=	$(findstring --enable-default-pie,${GCC_V_OUTPUT})
 
-ifeq ($(PIE_FOUND),1)
+ifneq ($(PIE_FOUND),)
 TF_CFLAGS		+=	-fno-PIE
 endif
 
@@ -488,6 +494,7 @@
 $(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))
@@ -530,6 +537,7 @@
 $(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}))
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
index cf32b31..0986a0a 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 @@
 	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 @@
 	/* 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 @@
 	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 @@
 	/* 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 @@
 	/* 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 @@
 	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/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
index b2b7953..e7528d3 100644
--- a/bl32/sp_min/aarch32/entrypoint.S
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -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
  */
@@ -17,6 +17,8 @@
 	.globl	sp_min_vector_table
 	.globl	sp_min_entrypoint
 	.globl	sp_min_warm_entrypoint
+	.globl	sp_min_handle_smc
+	.globl	sp_min_handle_fiq
 
 	.macro route_fiq_to_sp_min reg
 		/* -----------------------------------------------------
@@ -43,12 +45,12 @@
 vector_base sp_min_vector_table
 	b	sp_min_entrypoint
 	b	plat_panic_handler	/* Undef */
-	b	handle_smc		/* Syscall */
+	b	sp_min_handle_smc	/* Syscall */
 	b	plat_panic_handler	/* Prefetch abort */
 	b	plat_panic_handler	/* Data abort */
 	b	plat_panic_handler	/* Reserved */
 	b	plat_panic_handler	/* IRQ */
-	b	handle_fiq		/* FIQ */
+	b	sp_min_handle_fiq	/* FIQ */
 
 
 /*
@@ -151,7 +153,7 @@
 /*
  * SMC handling function for SP_MIN.
  */
-func handle_smc
+func sp_min_handle_smc
 	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
 	str	lr, [sp, #SMC_CTX_LR_MON]
 
@@ -199,12 +201,12 @@
 
 	/* `r0` points to `smc_ctx_t` */
 	b	sp_min_exit
-endfunc handle_smc
+endfunc sp_min_handle_smc
 
 /*
  * Secure Interrupts handling function for SP_MIN.
  */
-func handle_fiq
+func sp_min_handle_fiq
 #if !SP_MIN_WITH_SECURE_FIQ
 	b plat_panic_handler
 #else
@@ -242,7 +244,7 @@
 
 	b	sp_min_exit
 #endif
-endfunc handle_fiq
+endfunc sp_min_handle_fiq
 
 /*
  * The Warm boot entrypoint for SP_MIN.
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index 56489a3..67a1981 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -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
 #
@@ -26,6 +26,11 @@
 BL32_SOURCES		+=	lib/extensions/amu/aarch32/amu.c
 endif
 
+ifeq (${WORKAROUND_CVE_2017_5715},1)
+BL32_SOURCES		+=	bl32/sp_min/workaround_cve_2017_5715_bpiall.S	\
+				bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
+endif
+
 BL32_LINKERFILE	:=	bl32/sp_min/sp_min.ld.S
 
 # Include the platform-specific SP_MIN Makefile
diff --git a/bl32/sp_min/workaround_cve_2017_5715_bpiall.S b/bl32/sp_min/workaround_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..5387cef
--- /dev/null
+++ b/bl32/sp_min/workaround_cve_2017_5715_bpiall.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	workaround_bpiall_runtime_exceptions
+
+vector_base workaround_bpiall_runtime_exceptions
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the branch predictor, `r0` is a dummy register
+	 * and is unused.
+	 */
+	stcopr	r0, BPIALL
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	tst	sp, #2
+	bne	2f
+
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S b/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
new file mode 100644
index 0000000..9102b02
--- /dev/null
+++ b/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	workaround_icache_inv_runtime_exceptions
+
+vector_base workaround_icache_inv_runtime_exceptions
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the instruction cache, which we assume also
+	 * invalidates the branch predictor.  This may depend on
+	 * other CPU specific changes (e.g. an ACTLR setting).
+	 */
+	stcopr	r0, ICIALLU
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #2
+	bne	2f
+
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/docs/firmware-design.rst b/docs/firmware-design.rst
index 1f8fcc8..c383c5d 100644
--- a/docs/firmware-design.rst
+++ b/docs/firmware-design.rst
@@ -2574,9 +2574,9 @@
 ``ARM_ARCH_MINOR`` >= 2.
 
 -  The Common not Private (CnP) bit is enabled to indicate that multiple
-   Page Entries in the same Inner Shareable domain use the same translation
-   table entries for a given stage of translation for a particular translation
-   regime.
+   Processing Elements in the same Inner Shareable domain use the same
+   translation table entries for a given stage of translation for a particular
+   translation regime.
 
 ARMv7
 ~~~~~
diff --git a/docs/plat/hikey.rst b/docs/plat/hikey.rst
index 1c48104..99259f3 100644
--- a/docs/plat/hikey.rst
+++ b/docs/plat/hikey.rst
@@ -65,7 +65,7 @@
 
        BUILDFLAGS=-DSERIAL_BASE=0xF8015000
 
-   If your hikey hardware is built by LeMarker, nothing to do.
+   If your hikey hardware is built by LeMaker, nothing to do.
 
 -  Build it as debug mode. Create your own build script file or you could refer to **build\_uefi.sh** in l-loader git repository.
 
diff --git a/docs/plat/socionext-uniphier.rst b/docs/plat/socionext-uniphier.rst
index 2c652ac..590ff62 100644
--- a/docs/plat/socionext-uniphier.rst
+++ b/docs/plat/socionext-uniphier.rst
@@ -3,26 +3,28 @@
 
 
 Socionext UniPhier ARMv8-A SoCs use ARM Trusted Firmware as the secure world
-firmware, supporting BL1, BL2, and BL31.
+firmware, supporting BL2 and BL31.
 
-UniPhier SoC family implements its internal boot ROM, so BL1 is used as pseudo
-ROM (i.e. runs in RAM). The internal boot ROM loads 64KB [1]_ image from a
-non-volatile storage to the on-chip SRAM. Unfortunately, BL1 does not fit in
-the 64KB limit if `Trusted Board Boot`_ (TBB) is enabled. To solve this problem,
-Socionext provides a first stage loader called `UniPhier BL`_. This loader runs
-in the on-chip SRAM, initializes the DRAM, expands BL1 there, and hands the
-control over to it. Therefore, all images of ARM Trusted Firmware run in DRAM.
+UniPhier SoC family implements its internal boot ROM, which loads 64KB [1]_
+image from a non-volatile storage to the on-chip SRAM, and jumps over to it.
+ARM Trusted Firmware provides a special mode, BL2-AT-EL3, which enables BL2 to
+execute at EL3. It is useful for platforms with non-TF boot ROM, like UniPhier.
+Here, a problem is BL2 does not fit in the 64KB limit if `Trusted Board Boot`_
+(TBB) is enabled. To solve this issue, Socionext provides a first stage loader
+called `UniPhier BL`_. This loader runs in the on-chip SRAM, initializes the
+DRAM, expands BL2 there, and hands the control over to it. Therefore, all images
+of ARM Trusted Firmware run in DRAM.
 
 The UniPhier platform works with/without TBB. See below for the build process
 of each case. The image authentication for the UniPhier platform fully
 complies with the Trusted Board Boot Requirements (TBBR) specification.
 
 The UniPhier BL does not implement the authentication functionality, that is,
-it can not verify the BL1 image by itself. Instead, the UniPhier BL assures
-the BL1 validity in a different way; BL1 is GZIP-compressed and appended to
-the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL1
-fits in the 64KB limit. The concatenated image is loaded by the boot ROM
-(and verified if the chip fuses are blown).
+it can not verify the BL2 image by itself. Instead, the UniPhier BL assures
+the BL2 validity in a different way; BL2 is GZIP-compressed and appended to
+the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL2
+fits in the 64KB limit. The concatenated image is loaded by the internal boot
+ROM (and verified if the chip fuses are blown).
 
 
 Boot Flow
@@ -31,32 +33,32 @@
 1. The Boot ROM
 
    This is hard-wired ROM, so never corrupted. It loads the UniPhier BL (with
-   compressed-BL1 appended) into the on-chip SRAM. If the SoC fuses are blown,
+   compressed-BL2 appended) into the on-chip SRAM. If the SoC fuses are blown,
    the image is verified by the SoC's own method.
 
 2. UniPhier BL
 
    This runs in the on-chip SRAM. After the minimum SoC initialization and DRAM
-   setup, it decompresses the appended BL1 image into the DRAM, then jumps to
-   the BL1 entry.
+   setup, it decompresses the appended BL2 image into the DRAM, then jumps to
+   the BL2 entry.
 
-3. BL1
+3. BL2 (at EL3)
 
-   This runs in the DRAM. It extracts BL2 from FIP (Firmware Image Package).
-   If TBB is enabled, the BL2 is authenticated by the standard mechanism of ARM
-   Trusted Firmware.
+   This runs in the DRAM. It extracts more images such as BL31, BL33 (optionally
+   SCP_BL2, BL32 as well) from Firmware Image Package (FIP). If TBB is enabled,
+   they are all authenticated by the standard mechanism of ARM Trusted Firmware.
+   After loading all the images, it jumps to the BL31 entry.
 
-4. BL2, BL31, and more
+4. BL31, BL32, and BL33
 
-   They all run in the DRAM, and are authenticated by the standard mechanism if
-   TBB is enabled. See `Firmware Design`_ for details.
+   They all run in the DRAM. See `Firmware Design`_ for details.
 
 
 Basic Build
 -----------
 
-BL1 must be compressed for the reason above. The UniPhier's platform makefile
-provides a build target ``bl1_gzip`` for this.
+BL2 must be compressed for the reason above. The UniPhier's platform makefile
+provides a build target ``bl2_gzip`` for this.
 
 For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier
 SoCs. The U-Boot image (``u-boot.bin``) must be built in advance. For the build
@@ -64,11 +66,11 @@
 
 To build minimum functionality for UniPhier (without TBB)::
 
-    make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl1_gzip fip
+    make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl2_gzip fip
 
 Output images:
 
-- ``bl1.bin.gzip``
+- ``bl2.bin.gz``
 - ``fip.bin``
 
 
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 84bd2cd..7683ded 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1929,12 +1929,8 @@
 
 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]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2702,14 +2698,20 @@
 Crash Reporting mechanism (in BL31)
 -----------------------------------
 
-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.
+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.
 
-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.
+BL31 implements a crash reporting mechanism which prints the various registers
+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.
+
+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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2720,9 +2722,30 @@
     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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2736,6 +2759,12 @@
 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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2746,9 +2775,15 @@
 
 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/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
index 8b15d56..6f2510a 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 @@
 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 @@
 	 * 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 @@
 	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_core_flush(uintptr_t base_addr)
+	 * 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_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 @@
 	 * 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 @@
 
 	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/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
index f6a1532..fc357f8 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 @@
 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 @@
 	 * 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 @@
 	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 7cc04dd..f847ed5 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 0000000..c83e246
--- /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 0000000..15c3ba4
--- /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 9db6157..1b5d739 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
+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
-core_init_fail:
-	mov	w0, wzr
-	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 0000000..2fc0603
--- /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/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c
index 43f5af7..c9f84d7 100644
--- a/drivers/delay_timer/delay_timer.c
+++ b/drivers/delay_timer/delay_timer.c
@@ -7,6 +7,7 @@
 #include <assert.h>
 #include <delay_timer.h>
 #include <platform_def.h>
+#include <utils_def.h>
 
 /***********************************************************
  * The delay timer implementation
@@ -30,7 +31,8 @@
 
 	start = ops->get_timer_value();
 
-	total_delta = (usec * ops->clk_div) / ops->clk_mult;
+	/* Add an extra tick to avoid delaying less than requested. */
+	total_delta = div_round_up(usec * ops->clk_div, ops->clk_mult) + 1;
 
 	do {
 		/*
diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
index f9ccd57..b02209d 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 @@
 	mov	w3, #3
 	str	w3, [x0, #UARTMCR]
 	mov	w0, #1
-init_fail:
 	ret
-endfunc console_core_init
+init_fail:
+	mov	w0, #0
+	ret
+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 @@
 	 * 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 @@
 	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 d654b65..5db8854 100644
--- a/include/common/aarch32/el3_common_macros.S
+++ b/include/common/aarch32/el3_common_macros.S
@@ -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
  */
@@ -14,7 +14,7 @@
 	/*
 	 * Helper macro to initialise EL3 registers we care about.
 	 */
-	.macro el3_arch_init_common _exception_vectors
+	.macro el3_arch_init_common
 	/* ---------------------------------------------------------------------
 	 * SCTLR has already been initialised - read current value before
 	 * modifying.
@@ -34,15 +34,6 @@
 	isb
 
 	/* ---------------------------------------------------------------------
-	 * Set the exception vectors (VBAR/MVBAR).
-	 * ---------------------------------------------------------------------
-	 */
-	ldr	r0, =\_exception_vectors
-	stcopr	r0, VBAR
-	stcopr	r0, MVBAR
-	isb
-
-	/* ---------------------------------------------------------------------
 	 * Initialise SCR, setting all fields rather than relying on the hw.
 	 *
 	 * SCR.SIF: Enabled so that Secure state instruction fetches from
@@ -211,6 +202,15 @@
 	.endif /* _warm_boot_mailbox */
 
 	/* ---------------------------------------------------------------------
+	 * Set the exception vectors (VBAR/MVBAR).
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =\_exception_vectors
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	isb
+
+	/* ---------------------------------------------------------------------
 	 * It is a cold boot.
 	 * Perform any processor specific actions upon reset e.g. cache, TLB
 	 * invalidations etc.
@@ -218,7 +218,7 @@
 	 */
 	bl	reset_handler
 
-	el3_arch_init_common \_exception_vectors
+	el3_arch_init_common
 
 	.if \_secondary_cold_boot
 		/* -------------------------------------------------------------
diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S
new file mode 100644
index 0000000..0ebea2c
--- /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/drivers/arm/pl011.h b/include/drivers/arm/pl011.h
index cd259c5..06d7543 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 3aadde3..7ab6df0 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 da5cb8f..0629f57 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 0000000..cedce86
--- /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 0000000..4fca36f
--- /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/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h
index f258d45..9eba41a 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/aarch32/arch.h b/include/lib/aarch32/arch.h
index 4d2a5fc..134d534 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -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
  */
@@ -426,6 +426,8 @@
 #define TLBIMVAA	p15, 0, c8, c7, 3
 #define TLBIMVAAIS	p15, 0, c8, c3, 3
 #define BPIALLIS	p15, 0, c7, c1, 6
+#define BPIALL		p15, 0, c7, c5, 6
+#define ICIALLU		p15, 0, c7, c5, 0
 #define HSCTLR		p15, 4, c1, c0, 0
 #define HCR		p15, 4, c1, c1, 0
 #define HCPTR		p15, 4, c1, c1, 2
diff --git a/include/lib/aarch32/smcc_helpers.h b/include/lib/aarch32/smcc_helpers.h
index 53f1aa4..ed3b722 100644
--- a/include/lib/aarch32/smcc_helpers.h
+++ b/include/lib/aarch32/smcc_helpers.h
@@ -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
  */
@@ -22,7 +22,7 @@
 #define SMC_CTX_LR_MON		0x80
 #define SMC_CTX_SCR		0x84
 #define SMC_CTX_PMCR		0x88
-#define SMC_CTX_SIZE		0x8C
+#define SMC_CTX_SIZE		0x90
 
 #ifndef __ASSEMBLY__
 #include <cassert.h>
@@ -75,7 +75,13 @@
 	u_register_t lr_mon;
 	u_register_t scr;
 	u_register_t pmcr;
-} smc_ctx_t;
+	/*
+	 * The workaround for CVE-2017-5715 requires storing information in
+	 * the bottom 3 bits of the stack pointer.  Add a padding field to
+	 * force the size of the struct to be a multiple of 8.
+	 */
+	u_register_t pad;
+} smc_ctx_t __aligned(8);
 
 /*
  * Compile time assertions related to the 'smc_context' structure to
@@ -99,6 +105,7 @@
 CASSERT(SMC_CTX_SPSR_MON == __builtin_offsetof(smc_ctx_t, spsr_mon), \
 	assert_smc_ctx_spsr_mon_offset_mismatch);
 
+CASSERT((sizeof(smc_ctx_t) & 0x7) == 0, assert_smc_ctx_not_aligned);
 CASSERT(SMC_CTX_SIZE == sizeof(smc_ctx_t), assert_smc_ctx_size_mismatch);
 
 /* Convenience macros to return from SMC handler */
diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h
new file mode 100644
index 0000000..4b1f200
--- /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/cortex_a15.h b/include/lib/cpus/aarch32/cortex_a15.h
index 905c139..0f01a43 100644
--- a/include/lib/cpus/aarch32/cortex_a15.h
+++ b/include/lib/cpus/aarch32/cortex_a15.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,7 @@
 /*******************************************************************************
  * CPU Auxiliary Control register specific definitions.
  ******************************************************************************/
+#define CORTEX_A15_ACTLR_INV_BTB_BIT	(1 << 0)
 #define CORTEX_A15_ACTLR_SMP_BIT	(1 << 6)
 
 #endif /* __CORTEX_A15_H__ */
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index 185a1c1..ecb261a 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
@@ -24,6 +24,11 @@
  */
 #define DIV_ROUND_UP_2EVAL(n, d)	(((n) + (d) - 1) / (d))
 
+#define div_round_up(val, div) __extension__ ({	\
+	__typeof__(div) _div = (div);		\
+	((val) + _div - 1) / _div;		\
+})
+
 #define MIN(x, y) __extension__ ({	\
 	__typeof__(x) _x = (x);		\
 	__typeof__(y) _y = (y);		\
@@ -55,11 +60,6 @@
 #define round_down(value, boundary)		\
 	((value) & ~round_boundary(value, boundary))
 
-#define div_round_up(val, div) __extension__ ({	\
-	__typeof__(div) _div = (div);		\
-	round_up((val), _div)/_div;		\
-})
-
 /*
  * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise.
  * Both arguments must be unsigned pointer values (i.e. uintptr_t).
@@ -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/services/secure_partition.h b/include/services/secure_partition.h
index 334f761..93df2a1 100644
--- a/include/services/secure_partition.h
+++ b/include/services/secure_partition.h
@@ -35,27 +35,27 @@
  * partition.
  */
 typedef struct secure_partition_mp_info {
-	u_register_t		mpidr;
-	unsigned int		linear_id;
-	unsigned int		flags;
+	uint64_t		mpidr;
+	uint32_t		linear_id;
+	uint32_t		flags;
 } secure_partition_mp_info_t;
 
 typedef struct secure_partition_boot_info {
 	param_header_t		h;
-	uintptr_t		sp_mem_base;
-	uintptr_t		sp_mem_limit;
-	uintptr_t		sp_image_base;
-	uintptr_t		sp_stack_base;
-	uintptr_t		sp_heap_base;
-	uintptr_t		sp_ns_comm_buf_base;
-	uintptr_t		sp_shared_buf_base;
-	size_t			sp_image_size;
-	size_t			sp_pcpu_stack_size;
-	size_t			sp_heap_size;
-	size_t			sp_ns_comm_buf_size;
-	size_t			sp_shared_buf_size;
-	unsigned int		num_sp_mem_regions;
-	unsigned int		num_cpus;
+	uint64_t		sp_mem_base;
+	uint64_t		sp_mem_limit;
+	uint64_t		sp_image_base;
+	uint64_t		sp_stack_base;
+	uint64_t		sp_heap_base;
+	uint64_t		sp_ns_comm_buf_base;
+	uint64_t		sp_shared_buf_base;
+	uint64_t		sp_image_size;
+	uint64_t		sp_pcpu_stack_size;
+	uint64_t		sp_heap_size;
+	uint64_t		sp_ns_comm_buf_size;
+	uint64_t		sp_shared_buf_size;
+	uint32_t		num_sp_mem_regions;
+	uint32_t		num_cpus;
 	secure_partition_mp_info_t	*mp_info;
 } secure_partition_boot_info_t;
 
diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk
new file mode 100644
index 0000000..bbaa332
--- /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 0000000..64f8879
--- /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_a15.S b/lib/cpus/aarch32/cortex_a15.S
index 0d5a116..b6c61ab 100644
--- a/lib/cpus/aarch32/cortex_a15.S
+++ b/lib/cpus/aarch32/cortex_a15.S
@@ -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
  */
@@ -41,7 +41,46 @@
 	bx	lr
 endfunc cortex_a15_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A15. Must follow AAPCS.
+ */
+func cortex_a15_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a15, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a15_errata_report
+#endif
+
 func cortex_a15_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A15_ACTLR_INV_BTB_BIT
+	stcopr	r0, ACTLR
+	ldr	r0, =workaround_icache_inv_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a15_enable_smp
 endfunc cortex_a15_reset_func
 
diff --git a/lib/cpus/aarch32/cortex_a17.S b/lib/cpus/aarch32/cortex_a17.S
index 316d4f0..b84c126 100644
--- a/lib/cpus/aarch32/cortex_a17.S
+++ b/lib/cpus/aarch32/cortex_a17.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,7 +35,43 @@
 	bx	lr
 endfunc cortex_a17_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A17. Must follow AAPCS.
+ */
+func cortex_a17_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a17, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a17_errata_report
+#endif
+
 func cortex_a17_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a17_enable_smp
 endfunc cortex_a17_reset_func
 
diff --git a/lib/cpus/aarch32/cortex_a57.S b/lib/cpus/aarch32/cortex_a57.S
index 64a6d67..f446bff 100644
--- a/lib/cpus/aarch32/cortex_a57.S
+++ b/lib/cpus/aarch32/cortex_a57.S
@@ -332,6 +332,11 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859972
 
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A57.
 	 * Shall clobber: r0-r6
@@ -519,6 +524,7 @@
 	report_errata ERRATA_A57_829520, cortex_a57, 829520
 	report_errata ERRATA_A57_833471, cortex_a57, 833471
 	report_errata ERRATA_A57_859972, cortex_a57, 859972
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
 
 	pop	{r12, lr}
 	bx	lr
diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S
index 35b9bc2..56e91f5 100644
--- a/lib/cpus/aarch32/cortex_a72.S
+++ b/lib/cpus/aarch32/cortex_a72.S
@@ -87,6 +87,10 @@
 	b		cpu_rev_var_ls
 endfunc check_errata_859971
 
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
 
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A72.
@@ -236,6 +240,7 @@
 	 * checking functions of each errata.
 	 */
 	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
 
 	pop	{r12, lr}
 	bx	lr
diff --git a/lib/cpus/aarch32/cortex_a9.S b/lib/cpus/aarch32/cortex_a9.S
index 4f30f84..1fb10b2 100644
--- a/lib/cpus/aarch32/cortex_a9.S
+++ b/lib/cpus/aarch32/cortex_a9.S
@@ -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
  */
@@ -35,7 +35,43 @@
 	bx	lr
 endfunc cortex_a9_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A9. Must follow AAPCS.
+ */
+func cortex_a9_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a9, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a9_errata_report
+#endif
+
 func cortex_a9_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a9_enable_smp
 endfunc cortex_a9_reset_func
 
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index 683be47..c82ebfc 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -328,6 +328,15 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859972
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A57.
 	 * Shall clobber: x0-x19
@@ -518,7 +527,7 @@
 	report_errata ERRATA_A57_829520, cortex_a57, 829520
 	report_errata ERRATA_A57_833471, cortex_a57, 833471
 	report_errata ERRATA_A57_859972, cortex_a57, 859972
-
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
 
 	ldp	x8, x30, [sp], #16
 	ret
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
index 93821b7..9633aa8 100644
--- a/lib/cpus/aarch64/cortex_a72.S
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -97,6 +97,15 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859971
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A72.
 	 * -------------------------------------------------
@@ -249,6 +258,7 @@
 	 * checking functions of each errata.
 	 */
 	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
 
 	ldp	x8, x30, [sp], #16
 	ret
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
index c43f07e..11680a0 100644
--- a/lib/cpus/aarch64/cortex_a73.S
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -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
  */
@@ -114,6 +114,36 @@
 	b	cortex_a73_disable_smp
 endfunc cortex_a73_cluster_pwr_dwn
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a73_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a73, cve_2017_5715
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a73_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a73 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
index e66ad06..946f988 100644
--- a/lib/cpus/aarch64/cortex_a75.S
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -151,6 +151,27 @@
 	ret
 endfunc cortex_a75_reset_func
 
+func check_errata_cve_2017_5715
+	mrs	x0, id_aa64pfr0_el1
+	ubfx	x0, x0, #ID_AA64PFR0_CSV2_SHIFT, #ID_AA64PFR0_CSV2_LENGTH
+	/*
+	 * If the field equals to 1 then branch targets trained in one
+	 * context cannot affect speculative execution in a different context.
+	 */
+	cmp	x0, #1
+	beq	1f
+
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* ---------------------------------------------
 	 * HW will do the cache maintenance while powering down
 	 * ---------------------------------------------
@@ -167,6 +188,27 @@
 	ret
 endfunc cortex_a75_core_pwr_dwn
 
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a75_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a75, cve_2017_5715
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a75_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a75 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index 182679d..c679336 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,7 +27,7 @@
 #endif
 
 /* Errata format: BL stage, CPU, errata ID, message */
-#define ERRATA_FORMAT	"%s: %s: errata workaround for %s was %s\n"
+#define ERRATA_FORMAT	"%s: %s: CPU workaround for %s was %s\n"
 
 /*
  * Returns whether errata needs to be reported. Passed arguments are private to
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 643890f..a80a491 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -34,6 +34,10 @@
 # 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
 
@@ -94,6 +98,10 @@
 # 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/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 6729863..600af61 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -7,6 +7,7 @@
 #include <arm_config.h>
 #include <arm_def.h>
 #include <arm_spm_def.h>
+#include <arm_xlat_tables.h>
 #include <assert.h>
 #include <cci.h>
 #include <ccn.h>
@@ -128,6 +129,9 @@
 #if ENABLE_SPM && defined(IMAGE_BL31)
 const mmap_region_t plat_arm_secure_partition_mmap[] = {
 	V2M_MAP_IOFPGA_EL0, /* for the UART */
+	MAP_REGION_FLAT(DEVICE0_BASE,				\
+			DEVICE0_SIZE,				\
+			MT_DEVICE | MT_RO | MT_SECURE | MT_USER),
 	ARM_SP_IMAGE_MMAP,
 	ARM_SP_IMAGE_NS_BUF_MMAP,
 	ARM_SP_IMAGE_RW_MMAP,
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
index a87e7c6..cfc0c4f 100644
--- a/plat/common/aarch64/plat_common.c
+++ b/plat/common/aarch64/plat_common.c
@@ -39,11 +39,11 @@
 
 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 797a936..8526752 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,9 +57,63 @@
 	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
+
+	/* -----------------------------------------------------
+	 * void plat_crash_console_putc(int character)
+	 * Output through the normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_putc
+	b	console_putc
+endfunc plat_crash_console_putc
+
+	/* -----------------------------------------------------
+	 * 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
@@ -66,23 +121,14 @@
 	ret
 endfunc plat_crash_console_init
 
-	/* -----------------------------------------------------
-	 * Placeholder function which should be redefined by
-	 * each platform.
-	 * -----------------------------------------------------
-	 */
 func plat_crash_console_putc
 	ret
 endfunc plat_crash_console_putc
 
-	/* -----------------------------------------------------
-	 * Placeholder function which should be redefined by
-	 * each platform.
-	 * -----------------------------------------------------
-	 */
 func plat_crash_console_flush
 	ret
 endfunc plat_crash_console_flush
+#endif
 
 	/* -----------------------------------------------------
 	 * Placeholder function which should be redefined by
diff --git a/plat/hisilicon/hikey/hikey_bl2_setup.c b/plat/hisilicon/hikey/hikey_bl2_setup.c
index 86c205d..3f5e486 100644
--- a/plat/hisilicon/hikey/hikey_bl2_setup.c
+++ b/plat/hisilicon/hikey/hikey_bl2_setup.c
@@ -489,4 +489,5 @@
 
 void bl2_platform_setup(void)
 {
+	hikey_security_setup();
 }
diff --git a/plat/hisilicon/hikey/hikey_private.h b/plat/hisilicon/hikey/hikey_private.h
index a7709b2..da98734 100644
--- a/plat/hisilicon/hikey/hikey_private.h
+++ b/plat/hisilicon/hikey/hikey_private.h
@@ -44,6 +44,7 @@
 int hikey_flash(const char *arg);
 int hikey_oem(const char *arg);
 int hikey_reboot(const char *arg);
+void hikey_security_setup(void);
 
 const char *hikey_init_serialno(void);
 int hikey_read_serialno(struct random_serial_num *serialno);
diff --git a/plat/hisilicon/hikey/hikey_security.c b/plat/hisilicon/hikey/hikey_security.c
new file mode 100644
index 0000000..863ad2b
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_security.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <strings.h>
+#include <utils_def.h>
+#include "hikey_private.h"
+
+#define PORTNUM_MAX		5
+
+#define MDDRC_SECURITY_BASE	0xF7121000
+
+struct int_en_reg {
+	unsigned in_en:1;
+	unsigned reserved:31;
+};
+
+struct rgn_map_reg {
+	unsigned rgn_base_addr:24;
+	unsigned rgn_size:6;
+	unsigned reserved:1;
+	unsigned rgn_en:1;
+};
+
+struct rgn_attr_reg {
+	unsigned sp:4;
+	unsigned security_inv:1;
+	unsigned reserved_0:3;
+	unsigned mid_en:1;
+	unsigned mid_inv:1;
+	unsigned reserved_1:6;
+	unsigned rgn_en:1;
+	unsigned subrgn_disable:16;
+};
+
+static volatile struct int_en_reg *get_int_en_reg(uint32_t base)
+{
+	uint64_t addr = base + 0x20;
+	return (struct int_en_reg *)addr;
+}
+
+static volatile struct rgn_map_reg *get_rgn_map_reg(uint32_t base, int region, int port)
+{
+	uint64_t addr = base + 0x100 + 0x10 * region + 0x400 * (uint64_t)port;
+	return (struct rgn_map_reg *)addr;
+}
+
+static volatile struct rgn_attr_reg *get_rgn_attr_reg(uint32_t base, int region,
+					     int port)
+{
+	uint64_t addr = base + 0x104 + 0x10 * region + 0x400 * (uint64_t)port;
+	return (struct rgn_attr_reg *)addr;
+}
+
+/*
+ * Configure secure memory region
+ * region_size must be a power of 2 and at least 64KB
+ * region_base must be region_size aligned
+ */
+static void sec_protect(uint32_t region_base, uint32_t region_size,
+			int region)
+{
+	volatile struct int_en_reg *int_en;
+	volatile struct rgn_map_reg *rgn_map;
+	volatile struct rgn_attr_reg *rgn_attr;
+	uint32_t i = 0;
+
+	/* ensure secure region number is between 1-15 */
+	assert(region > 0 && region < 16);
+	/* ensure secure region size is a power of 2 >= 64KB */
+	assert(IS_POWER_OF_TWO(region_size) && region_size >= 0x10000);
+	/* ensure secure region address is aligned to region size */
+	assert(!(region_base & (region_size - 1)));
+
+	INFO("BL2: TrustZone: protecting %u bytes of memory at 0x%x\n", region_size,
+	     region_base);
+
+	int_en = get_int_en_reg(MDDRC_SECURITY_BASE);
+	int_en->in_en = 0x1;
+
+	for (i = 0; i < PORTNUM_MAX; i++) {
+		rgn_map = get_rgn_map_reg(MDDRC_SECURITY_BASE, region, i);
+		rgn_attr = get_rgn_attr_reg(MDDRC_SECURITY_BASE, region, i);
+		rgn_map->rgn_base_addr = region_base >> 16;
+		rgn_attr->subrgn_disable = 0x0;
+		rgn_attr->sp = (i == 3) ? 0xC : 0x0;
+		rgn_map->rgn_size = __builtin_ffs(region_size) - 2;
+		rgn_map->rgn_en = 0x1;
+	}
+}
+
+/*******************************************************************************
+ * Initialize the secure environment.
+ ******************************************************************************/
+void hikey_security_setup(void)
+{
+	sec_protect(DDR_SEC_BASE, DDR_SEC_SIZE, 1);
+	sec_protect(DDR_SDP_BASE, DDR_SDP_SIZE, 2);
+}
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
index 524fa6a..c8a2992 100644
--- a/plat/hisilicon/hikey/platform.mk
+++ b/plat/hisilicon/hikey/platform.mk
@@ -78,6 +78,7 @@
 				drivers/synopsys/emmc/dw_mmc.c		\
 				plat/hisilicon/hikey/aarch64/hikey_helpers.S \
 				plat/hisilicon/hikey/hikey_bl2_setup.c	\
+				plat/hisilicon/hikey/hikey_security.c   \
 				plat/hisilicon/hikey/hikey_ddr.c	\
 				plat/hisilicon/hikey/hikey_io_storage.c	\
 				plat/hisilicon/hikey/hisi_dvfs.c	\
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
index f685f9c..f0d15a3 100644
--- a/plat/hisilicon/hikey960/hikey960_bl31_setup.c
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -16,6 +16,8 @@
 #include <gicv2.h>
 #include <hi3660.h>
 #include <hisi_ipc.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
 #include <platform_def.h>
 
 #include "hikey960_def.h"
@@ -167,6 +169,37 @@
 	hisi_ipc_init();
 }
 
+#ifdef SPD_none
+static uint64_t hikey_debug_fiq_handler(uint32_t id,
+					uint32_t flags,
+					void *handle,
+					void *cookie)
+{
+	int intr, intr_raw;
+
+	/* Acknowledge interrupt */
+	intr_raw = plat_ic_acknowledge_interrupt();
+	intr = plat_ic_get_interrupt_id(intr_raw);
+	ERROR("Invalid interrupt: intr=%d\n", intr);
+	console_flush();
+	panic();
+
+	return 0;
+}
+#endif
+
 void bl31_plat_runtime_setup(void)
 {
+#ifdef SPD_none
+	uint32_t flags;
+	int32_t rc;
+
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+					     hikey_debug_fiq_handler,
+					     flags);
+	if (rc != 0)
+		panic();
+#endif
 }
diff --git a/plat/hisilicon/poplar/bl1_plat_setup.c b/plat/hisilicon/poplar/bl1_plat_setup.c
index c65e29e..7d6f10c 100644
--- a/plat/hisilicon/poplar/bl1_plat_setup.c
+++ b/plat/hisilicon/poplar/bl1_plat_setup.c
@@ -9,6 +9,8 @@
 #include <bl_common.h>
 #include <console.h>
 #include <debug.h>
+#include <dw_mmc.h>
+#include <emmc.h>
 #include <errno.h>
 #include <generic_delay_timer.h>
 #include <mmio.h>
@@ -71,6 +73,9 @@
 void bl1_platform_setup(void)
 {
 	int i;
+#if !POPLAR_RECOVERY
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
 
 	generic_delay_timer_init();
 
@@ -78,6 +83,12 @@
 	for (i = 0; i < GPIO_MAX; i++)
 		pl061_gpio_register(GPIO_BASE(i), i);
 
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL1: initializing emmc\n");
+	dw_mmc_init(&params);
+#endif
+
 	plat_io_setup();
 }
 
diff --git a/plat/hisilicon/poplar/bl2_plat_setup.c b/plat/hisilicon/poplar/bl2_plat_setup.c
index db507c3..7edfab7 100644
--- a/plat/hisilicon/poplar/bl2_plat_setup.c
+++ b/plat/hisilicon/poplar/bl2_plat_setup.c
@@ -9,6 +9,8 @@
 #include <bl_common.h>
 #include <console.h>
 #include <debug.h>
+#include <dw_mmc.h>
+#include <emmc.h>
 #include <errno.h>
 #include <generic_delay_timer.h>
 #include <mmio.h>
@@ -181,12 +183,24 @@
 
 void bl2_early_platform_setup(meminfo_t *mem_layout)
 {
+#if !POPLAR_RECOVERY
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
+
 	console_init(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE);
 
 	/* Enable arch timer */
 	generic_delay_timer_init();
 
 	bl2_tzram_layout = *mem_layout;
+
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL2: initializing emmc\n");
+	dw_mmc_init(&params);
+#endif
+
+	plat_io_setup();
 }
 
 void bl2_plat_arch_setup(void)
@@ -201,7 +215,6 @@
 
 void bl2_platform_setup(void)
 {
-	plat_io_setup();
 }
 
 unsigned long plat_get_ns_image_entrypoint(void)
diff --git a/plat/hisilicon/poplar/include/hi3798cv200.h b/plat/hisilicon/poplar/include/hi3798cv200.h
index 540d0aa..125b048 100644
--- a/plat/hisilicon/poplar/include/hi3798cv200.h
+++ b/plat/hisilicon/poplar/include/hi3798cv200.h
@@ -7,6 +7,8 @@
 #ifndef __HI3798cv200_H__
 #define __HI3798cv200_H__
 
+#include <utils_def.h>
+
 /* PL011 */
 #define PL011_UART0_BASE		(0xF8B00000)
 #define PL011_BAUDRATE			(115200)
@@ -63,11 +65,11 @@
 #define EMMC_CLK_50M			(1 << 8)
 #define EMMC_CLK_25M			(2 << 8)
 
-#define EMMC_DESC_SIZE			(0xF0000)
+#define EMMC_DESC_SIZE			U(0x00100000) /* 1MB */
 #define EMMC_INIT_PARAMS(base)				\
 	{	.bus_width = EMMC_BUS_WIDTH_8,		\
 		.clk_rate = 25 * 1000 * 1000,		\
-		.desc_base = (base) - EMMC_DESC_SIZE,	\
+		.desc_base = (base),	\
 		.desc_size = EMMC_DESC_SIZE,		\
 		.flags =  EMMC_FLAG_CMD23,		\
 		.reg_base = REG_BASE_MCI,		\
diff --git a/plat/hisilicon/poplar/include/platform_def.h b/plat/hisilicon/poplar/include/platform_def.h
index 3d1ad9b..c0f8371 100644
--- a/plat/hisilicon/poplar/include/platform_def.h
+++ b/plat/hisilicon/poplar/include/platform_def.h
@@ -12,6 +12,7 @@
 #include <gic_common.h>
 #include <interrupt_props.h>
 #include <tbbr/tbbr_img_def.h>
+#include <utils_def.h>
 #include "hi3798cv200.h"
 #include "poplar_layout.h"		/* BL memory region sizes, etc */
 
@@ -53,13 +54,12 @@
 #define POPLAR_DRAM_ID	1
 
 /*
- * DDR for OP-TEE (28MB from 0x02200000 -0x04000000) is divided in several
+ * DDR for OP-TEE (26MB from 0x02400000 -0x04000000) is divided in several
  * regions:
  *   - Secure DDR (default is the top 16MB) used by OP-TEE
  *   - Non-secure DDR (4MB) reserved for OP-TEE's future use
  *   - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature
  *   - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB)
- *   - Non-secure DDR (2MB) reserved for OP-TEE's future use
  */
 #define DDR_SEC_SIZE			0x01000000
 #define DDR_SEC_BASE			0x03000000
@@ -96,6 +96,11 @@
 #endif /* SPD_none */
 #endif
 
+#define POPLAR_EMMC_DATA_BASE U(0x02200000)
+#define POPLAR_EMMC_DATA_SIZE EMMC_DESC_SIZE
+#define POPLAR_EMMC_DESC_BASE (POPLAR_EMMC_DATA_BASE + POPLAR_EMMC_DATA_SIZE)
+#define POPLAR_EMMC_DESC_SIZE EMMC_DESC_SIZE
+
 #define PLAT_POPLAR_NS_IMAGE_OFFSET	0x37000000
 
 /* Page table and MMU setup constants */
diff --git a/plat/hisilicon/poplar/include/poplar_layout.h b/plat/hisilicon/poplar/include/poplar_layout.h
index e0b5618..9ce0434 100644
--- a/plat/hisilicon/poplar/include/poplar_layout.h
+++ b/plat/hisilicon/poplar/include/poplar_layout.h
@@ -12,8 +12,8 @@
  */
 
 /*
- * When Poplar is powered on, boot ROM loads the initial content of
- * boot media into low memory, verifies it, and begins executing it
+ * When Poplar is powered on, boot ROM verifies the initial content of
+ * boot media, loads it into low memory, and begins executing it
  * in 32-bit mode.  The image loaded is "l-loader.bin", which contains
  * a small amount code along with an embedded ARM Trusted Firmware
  * BL1 image.  The main purpose of "l-loader" is to prepare the
@@ -78,12 +78,36 @@
 #define BL1_OFFSET			0x0000D000	/* page multiple */
 #define FIP_BASE			0x02040000
 
+/*
+ * FIP_BASE_EMMC = 0x40000 - 0x1000
+ * = fip.bin offset - l-loader text offset
+ * in l-loader.bin
+ */
+#define FIP_BASE_EMMC			0x0003f000
+
 #define BL1_RO_SIZE			0x00008000	/* page multiple */
 #define BL1_RW_SIZE			0x00008000	/* page multiple */
 #define BL1_SIZE			(BL1_RO_SIZE + BL1_RW_SIZE)
 #define BL2_SIZE			0x0000c000	/* page multiple */
 #define BL31_SIZE			0x00014000
+#if !POPLAR_RECOVERY
+/*
+ * emmc partition1 4096KB
+ * - l-loader.bin 1984KB
+ * |- l-loader + bl1.bin 256KB
+ * |- fip.bin 1728KB (0x001b0000)
+ * - u-boot persistent data 64KB
+ * - uefi persistent data 2048KB
+ */
+#define FIP_SIZE			0x001b0000  /* absolute max */
+#else
+/*
+ * same as above, but bootrom can only load an image (l-loader.bin) of
+ * 1024KB max, so after deducting the size of l-loader + bl1.bin (256KB),
+ * that leaves 768KB (0x000c0000) for fip.bin
+ */
 #define FIP_SIZE			0x000c0000  /* absolute max */
+#endif
 
      /* BL1_OFFSET */			/* (Defined above) */
 #define BL1_BASE			(LLOADER_TEXT_BASE + BL1_OFFSET)
diff --git a/plat/hisilicon/poplar/plat_storage.c b/plat/hisilicon/poplar/plat_storage.c
index ab94cba..468e229 100644
--- a/plat/hisilicon/poplar/plat_storage.c
+++ b/plat/hisilicon/poplar/plat_storage.c
@@ -7,6 +7,7 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
+#include <emmc.h>
 #include <firmware_image_package.h>
 #include <io_block.h>
 #include <io_driver.h>
@@ -21,19 +22,41 @@
 #include <utils.h>
 #include "platform_def.h"
 
+#if !POPLAR_RECOVERY
+static const io_dev_connector_t *emmc_dev_con;
+static uintptr_t emmc_dev_handle;
+static int open_emmc(const uintptr_t spec);
+
+static const io_block_spec_t emmc_fip_spec = {
+	.offset		= FIP_BASE_EMMC,
+	.length		= FIP_SIZE
+};
+
+static const io_block_dev_spec_t emmc_dev_spec = {
+	.buffer		= {
+		.offset	= POPLAR_EMMC_DATA_BASE,
+		.length	= POPLAR_EMMC_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= emmc_read_blocks,
+		.write	= emmc_write_blocks,
+	},
+	.block_size	= EMMC_BLOCK_SIZE,
+};
+#else
 static const io_dev_connector_t *mmap_dev_con;
-static const io_dev_connector_t *fip_dev_con;
-
 static uintptr_t mmap_dev_handle;
-static uintptr_t fip_dev_handle;
-
 static int open_mmap(const uintptr_t spec);
-static int open_fip(const uintptr_t spec);
 
 static const io_block_spec_t loader_fip_spec = {
 	.offset		= FIP_BASE,
 	.length		= FIP_SIZE
 };
+#endif
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static int open_fip(const uintptr_t spec);
 
 static const io_uuid_spec_t bl2_uuid_spec = {
 	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
@@ -58,11 +81,19 @@
 };
 
 static const struct plat_io_policy policies[] = {
+#if !POPLAR_RECOVERY
+	[FIP_IMAGE_ID] = {
+		&emmc_dev_handle,
+		(uintptr_t)&emmc_fip_spec,
+		open_emmc
+	},
+#else
 	[FIP_IMAGE_ID] = {
 		&mmap_dev_handle,
 		(uintptr_t)&loader_fip_spec,
 		open_mmap
 	},
+#endif
 	[BL2_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl2_uuid_spec,
@@ -85,6 +116,28 @@
 	},
 };
 
+#if !POPLAR_RECOVERY
+static int open_emmc(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(emmc_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			INFO("Using eMMC\n");
+			io_close(local_image_handle);
+		} else {
+			ERROR("error opening emmc\n");
+		}
+	} else {
+		ERROR("error initializing emmc\n");
+	}
+
+	return result;
+}
+#else
 static int open_mmap(const uintptr_t spec)
 {
 	int result;
@@ -94,11 +147,18 @@
 	if (result == 0) {
 		result = io_open(mmap_dev_handle, spec, &local_image_handle);
 		if (result == 0) {
+			INFO("Using mmap\n");
 			io_close(local_image_handle);
+		} else {
+			ERROR("error opening mmap\n");
 		}
+	} else {
+		ERROR("error initializing mmap\n");
 	}
+
 	return result;
 }
+#endif
 
 static int open_fip(const uintptr_t spec)
 {
@@ -109,12 +169,13 @@
 	if (result == 0) {
 		result = io_open(fip_dev_handle, spec, &local_image_handle);
 		if (result == 0) {
+			INFO("Using FIP\n");
 			io_close(local_image_handle);
 		} else {
-			VERBOSE("error opening fip\n");
+			ERROR("error opening fip\n");
 		}
 	} else {
-		VERBOSE("error initializing fip\n");
+		ERROR("error initializing fip\n");
 	}
 
 	return result;
@@ -142,17 +203,31 @@
 {
 	int result;
 
+#if !POPLAR_RECOVERY
+	result = register_io_dev_block(&emmc_dev_con);
+#else
 	result = register_io_dev_memmap(&mmap_dev_con);
+#endif
 	assert(result == 0);
 
 	result = register_io_dev_fip(&fip_dev_con);
 	assert(result == 0);
 
+#if !POPLAR_RECOVERY
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+#else
 	result = io_dev_open(fip_dev_con, (uintptr_t)&loader_fip_spec,
 				&fip_dev_handle);
+#endif
 	assert(result == 0);
 
+#if !POPLAR_RECOVERY
+	result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec,
+				&emmc_dev_handle);
+#else
 	result = io_dev_open(mmap_dev_con, (uintptr_t)NULL, &mmap_dev_handle);
+#endif
 	assert(result == 0);
 
 	(void) result;
diff --git a/plat/hisilicon/poplar/platform.mk b/plat/hisilicon/poplar/platform.mk
index 818e311..2dbbac6 100644
--- a/plat/hisilicon/poplar/platform.mk
+++ b/plat/hisilicon/poplar/platform.mk
@@ -15,6 +15,9 @@
 endif
 $(eval $(call add_define,POPLAR_TSP_RAM_LOCATION_ID))
 
+POPLAR_RECOVERY		:= 0
+$(eval $(call add_define,POPLAR_RECOVERY))
+
 NEED_BL33			:= yes
 
 COLD_BOOT_SINGLE_CPU		:= 1
@@ -36,6 +39,7 @@
 			-Iinclude/plat/arm/common/		\
 			-Iplat/hisilicon/poplar			\
 			-Iinclude/common/tbbr			\
+			-Iinclude/drivers/synopsys		\
 			-Iinclude/drivers/io
 
 PLAT_BL_COMMON_SOURCES	:=						\
@@ -54,6 +58,8 @@
 BL1_SOURCES	+=							\
 		lib/cpus/aarch64/cortex_a53.S				\
 		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/emmc/emmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
 		drivers/io/io_storage.c					\
 		drivers/io/io_block.c					\
 		drivers/gpio/gpio.c					\
@@ -65,6 +71,8 @@
 
 BL2_SOURCES	+=      						\
 		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/emmc/emmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
 		drivers/io/io_storage.c					\
 		drivers/io/io_block.c					\
 		drivers/io/io_fip.c					\
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
index abfb5a7..f415f87 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 @@
 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 292f0dd..6199eda 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 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 @@
 
 	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 be1a9fa..6b3cb6a 100644
--- a/plat/rockchip/common/include/plat_macros.S
+++ b/plat/rockchip/common/include/plat_macros.S
@@ -38,14 +38,14 @@
 	 * 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 @@
 	/* 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 aa13f87..7109907 100644
--- a/plat/rockchip/common/include/plat_params.h
+++ b/plat/rockchip/common/include/plat_params.h
@@ -56,6 +56,7 @@
 	PARAM_POWEROFF,
 	PARAM_SUSPEND_GPIO,
 	PARAM_SUSPEND_APIO,
+	PARAM_COREBOOT_TABLE,
 };
 
 struct apio_info {
@@ -89,4 +90,9 @@
 	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 b37acb7..65afe87 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 @@
 			       sizeof(struct bl31_apio_param));
 			suspend_apio = &param_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 5de4680..6e4d5b4 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -49,6 +49,9 @@
 				${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 d3c6eef..ad204e9 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -49,6 +49,9 @@
 				${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 482c7b7..1997dfc 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -66,6 +66,9 @@
 			${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/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h
index cc046eb..546670e 100644
--- a/plat/socionext/uniphier/include/platform_def.h
+++ b/plat/socionext/uniphier/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,29 +27,20 @@
 #define PLAT_MAX_OFF_STATE		2
 #define PLAT_MAX_RET_STATE		1
 
-#define UNIPHIER_SEC_DRAM_BASE		0x81000000
+#define UNIPHIER_SEC_DRAM_BASE		0x80000000
 #define UNIPHIER_SEC_DRAM_LIMIT		0x82000000
 #define UNIPHIER_SEC_DRAM_SIZE		((UNIPHIER_SEC_DRAM_LIMIT) - \
 					 (UNIPHIER_SEC_DRAM_BASE))
 
-#define BL1_RO_BASE			0x80000000
-#define BL1_RO_LIMIT			0x80018000
-#define BL1_RW_LIMIT			(UNIPHIER_SEC_DRAM_LIMIT)
-#define BL1_RW_BASE			((BL1_RW_LIMIT) - 0x00040000)
+#define BL2_BASE			(UNIPHIER_SEC_DRAM_BASE)
+#define BL2_LIMIT			((BL2_BASE) + 0x00020000)
 
-#define BL2_LIMIT			(BL1_RW_BASE)
-#define BL2_BASE			((BL2_LIMIT) - 0x00040000)
-
-#define BL31_BASE			(UNIPHIER_SEC_DRAM_BASE)
+#define BL31_BASE			(BL2_LIMIT)
 #define BL31_LIMIT			((BL31_BASE) + 0x00080000)
 
 #define BL32_BASE			(BL31_LIMIT)
 #define BL32_LIMIT			(UNIPHIER_SEC_DRAM_LIMIT)
 
-#define UNIPHIER_BLOCK_BUF_SIZE		0x00400000
-#define UNIPHIER_BLOCK_BUF_BASE		((BL2_BASE) - \
-					 (UNIPHIER_BLOCK_BUF_SIZE))
-
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
 
@@ -63,7 +54,6 @@
 
 #define TSP_SEC_MEM_BASE		(BL32_BASE)
 #define TSP_SEC_MEM_SIZE		((BL32_LIMIT) - (BL32_BASE))
-#define TSP_PROGBITS_LIMIT		(UNIPHIER_BLOCK_BUF_BASE)
 #define TSP_IRQ_SEC_PHY_TIMER		29
 
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
index f99bbf5..18b56a0 100644
--- a/plat/socionext/uniphier/platform.mk
+++ b/plat/socionext/uniphier/platform.mk
@@ -1,16 +1,17 @@
 #
-# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
-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
-override ENABLE_SVE_FOR_NS	:= 0
+override BL2_AT_EL3			:= 1
+override COLD_BOOT_SINGLE_CPU		:= 1
+override ENABLE_PLAT_COMPAT		:= 0
+override LOAD_IMAGE_V2			:= 1
+override PROGRAMMABLE_RESET_ADDRESS	:= 1
+override USE_COHERENT_MEM		:= 1
+override USE_TBBR_DEFS			:= 1
+override ENABLE_SVE_FOR_NS		:= 0
 
 # Cortex-A53 revision r0p4-51rel0
 # needed for LD20, unneeded for LD11, PXs3 (no ACE)
@@ -28,18 +29,7 @@
 PLAT_PATH		:=	plat/socionext/uniphier
 PLAT_INCLUDES		:=	-I$(PLAT_PATH)/include
 
-# IO sources for BL1, BL2
-IO_SOURCES		:=	drivers/io/io_block.c			\
-				drivers/io/io_fip.c			\
-				drivers/io/io_memmap.c			\
-				drivers/io/io_storage.c			\
-				$(PLAT_PATH)/uniphier_boot_device.c	\
-				$(PLAT_PATH)/uniphier_emmc.c		\
-				$(PLAT_PATH)/uniphier_io_storage.c	\
-				$(PLAT_PATH)/uniphier_nand.c		\
-				$(PLAT_PATH)/uniphier_usb.c
-
-# common sources for BL1, BL2, BL31
+# common sources for BL2, BL31 (and BL32 if SPD=tspd)
 PLAT_BL_COMMON_SOURCES	+=	drivers/console/aarch64/console.S	\
 				$(PLAT_PATH)/uniphier_console.S		\
 				$(PLAT_PATH)/uniphier_helpers.S		\
@@ -47,17 +37,21 @@
 				$(PLAT_PATH)/uniphier_xlat_setup.c	\
 				${XLAT_TABLES_LIB_SRCS}
 
-BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
-				lib/cpus/aarch64/cortex_a72.S		\
-				$(PLAT_PATH)/uniphier_bl1_helpers.S	\
-				$(PLAT_PATH)/uniphier_bl1_setup.c	\
-				$(IO_SOURCES)
-
 BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
 				$(PLAT_PATH)/uniphier_bl2_setup.c	\
+				$(PLAT_PATH)/uniphier_boot_device.c	\
+				$(PLAT_PATH)/uniphier_emmc.c		\
 				$(PLAT_PATH)/uniphier_image_desc.c	\
+				$(PLAT_PATH)/uniphier_io_storage.c	\
+				$(PLAT_PATH)/uniphier_nand.c		\
 				$(PLAT_PATH)/uniphier_scp.c		\
-				$(IO_SOURCES)
+				$(PLAT_PATH)/uniphier_usb.c
 
 BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
 				drivers/arm/gic/common/gic_common.c	\
@@ -83,7 +77,7 @@
 
 PLAT_INCLUDES		+=	-Iinclude/common/tbbr
 
-TBB_SOURCES		:=	drivers/auth/auth_mod.c			\
+BL2_SOURCES		+=	drivers/auth/auth_mod.c			\
 				drivers/auth/crypto_mod.c		\
 				drivers/auth/img_parser_mod.c		\
 				drivers/auth/tbbr/tbbr_cot.c		\
@@ -91,14 +85,10 @@
 				$(PLAT_PATH)/uniphier_rotpk.S		\
 				$(PLAT_PATH)/uniphier_tbbr.c
 
-BL1_SOURCES		+=	$(TBB_SOURCES)
-BL2_SOURCES		+=	$(TBB_SOURCES)
-
 ROT_KEY			= $(BUILD_PLAT)/rot_key.pem
 ROTPK_HASH		= $(BUILD_PLAT)/rotpk_sha256.bin
 
 $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
-$(BUILD_PLAT)/bl1/uniphier_rotpk.o: $(ROTPK_HASH)
 $(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH)
 
 certificates: $(ROT_KEY)
@@ -113,8 +103,8 @@
 
 endif
 
-.PHONY: bl1_gzip
-bl1_gzip: $(BUILD_PLAT)/bl1.bin.gzip
-%.gzip: %
+.PHONY: bl2_gzip
+bl2_gzip: $(BUILD_PLAT)/bl2.bin.gz
+%.gz: %
 	@echo "  GZIP    $@"
 	$(Q)gzip -n -f -9 $< --stdout > $@
diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h
index 95b29b8..2af30df 100644
--- a/plat/socionext/uniphier/uniphier.h
+++ b/plat/socionext/uniphier/uniphier.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -67,7 +67,9 @@
 unsigned int uniphier_calc_core_pos(u_register_t mpidr);
 
 #define UNIPHIER_NS_DRAM_BASE		0x84000000
-#define UNIPHIER_NS_DRAM_SIZE		0x01000000
+#define UNIPHIER_NS_DRAM_LIMIT		0x85000000
+#define UNIPHIER_NS_DRAM_SIZE		((UNIPHIER_NS_DRAM_LIMIT) - \
+					 (UNIPHIER_NS_DRAM_BASE))
 
 #define UNIPHIER_BL33_BASE		(UNIPHIER_NS_DRAM_BASE)
 #define UNIPHIER_BL33_MAX_SIZE		0x00100000
@@ -76,4 +78,9 @@
 					 (UNIPHIER_BL33_MAX_SIZE))
 #define UNIPHIER_SCP_MAX_SIZE		0x00020000
 
+#define UNIPHIER_BLOCK_BUF_BASE		((UNIPHIER_SCP_BASE) + \
+					 (UNIPHIER_SCP_MAX_SIZE))
+#define UNIPHIER_BLOCK_BUF_SIZE		((UNIPHIER_NS_DRAM_LIMIT) - \
+					 (UNIPHIER_BLOCK_BUF_BASE))
+
 #endif /* __UNIPHIER_H__ */
diff --git a/plat/socionext/uniphier/uniphier_bl1_helpers.S b/plat/socionext/uniphier/uniphier_bl1_helpers.S
deleted file mode 100644
index 5818565..0000000
--- a/plat/socionext/uniphier/uniphier_bl1_helpers.S
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <asm_macros.S>
-
-	.globl	plat_get_my_entrypoint
-
-func plat_get_my_entrypoint
-	mov	x0, #0
-	ret
-endfunc plat_get_my_entrypoint
diff --git a/plat/socionext/uniphier/uniphier_bl1_setup.c b/plat/socionext/uniphier/uniphier_bl1_setup.c
deleted file mode 100644
index da7740a..0000000
--- a/plat/socionext/uniphier/uniphier_bl1_setup.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch_helpers.h>
-#include <bl_common.h>
-#include <console.h>
-#include <debug.h>
-#include <errno.h>
-#include <platform.h>
-#include <platform_def.h>
-#include <xlat_mmu_helpers.h>
-
-#include "uniphier.h"
-
-void bl1_early_platform_setup(void)
-{
-	uniphier_console_setup();
-}
-
-void bl1_plat_arch_setup(void)
-{
-	uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
-			    NULL);
-	enable_mmu_el3(0);
-}
-
-void bl1_platform_setup(void)
-{
-	unsigned int soc;
-	int ret;
-
-	soc = uniphier_get_soc_id();
-	if (soc == UNIPHIER_SOC_UNKNOWN) {
-		ERROR("unsupported SoC\n");
-		plat_error_handler(-ENOTSUP);
-	}
-
-	ret = uniphier_io_setup(soc);
-	if (ret) {
-		ERROR("failed to setup io devices\n");
-		plat_error_handler(ret);
-	}
-}
-
-static meminfo_t uniphier_tzram_layout = {
-	.total_base = UNIPHIER_SEC_DRAM_BASE,
-	.total_size = UNIPHIER_SEC_DRAM_SIZE,
-};
-
-meminfo_t *bl1_plat_sec_mem_layout(void)
-{
-	return &uniphier_tzram_layout;
-}
diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c
index b83e700..daf0c45 100644
--- a/plat/socionext/uniphier/uniphier_bl2_setup.c
+++ b/plat/socionext/uniphier/uniphier_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,13 +15,11 @@
 
 #include "uniphier.h"
 
-static meminfo_t uniphier_bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
 static int uniphier_bl2_kick_scp;
 
-void bl2_early_platform_setup(meminfo_t *mem_layout)
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+				  u_register_t x2, u_register_t x3)
 {
-	uniphier_bl2_tzram_layout = *mem_layout;
-
 	uniphier_console_setup();
 }
 
@@ -32,7 +30,7 @@
 	{ .size = 0 },
 };
 
-void bl2_plat_arch_setup(void)
+void bl2_el3_plat_arch_setup(void)
 {
 	unsigned int soc;
 	int skip_scp = 0;
@@ -40,7 +38,7 @@
 
 	uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
 			    uniphier_bl2_mmap);
-	enable_mmu_el1(0);
+	enable_mmu_el3(0);
 
 	soc = uniphier_get_soc_id();
 	if (soc == UNIPHIER_SOC_UNKNOWN) {
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 33c451e..e70ff36 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -543,7 +543,6 @@
 		log_dbgx("Metadata size: %zu bytes", buf_size);
 
 	xfwrite(buf, buf_size, fp, filename);
-	free(buf);
 
 	if (verbose)
 		log_dbgx("Payload size: %zu bytes", payload_size);
@@ -566,6 +565,7 @@
 	while (pad_size--)
 		fputc(0x0, fp);
 
+	free(buf);
 	fclose(fp);
 	return 0;
 }