summaryrefslogtreecommitdiff
path: root/drivers/coreboot
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2017-06-13 15:53:45 -0700
committerJulius Werner <jwerner@chromium.org>2018-01-19 15:21:12 -0800
commit1c5f5031f38ed77688298d419727a6f0930e0673 (patch)
tree0ce47576b2e24073a1f22ce3d808da2364e3f9c6 /drivers/coreboot
parent890abc33e46349fb01aed443ad7128b82ba34f3d (diff)
coreboot: Add support for CBMEM console
coreboot supports an in-memory console to store firmware logs even when no serial console is available. It is widely supported by coreboot-compatible bootloaders (including SeaBIOS and GRUB) and can be read by the Linux kernel. This patch allows BL31 to add its own log messages to this console. The driver will be registered automatically if coreboot support is compiled in and detects the presence of a console buffer in the coreboot tables. Change-Id: I31254dfa0c2fdeb7454634134b5707b4b4154907 Signed-off-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'drivers/coreboot')
-rw-r--r--drivers/coreboot/cbmem_console/aarch64/cbmem_console.S101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
new file mode 100644
index 00000000..2fc06033
--- /dev/null
+++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <cbmem_console.h>
+#include <console_macros.S>
+
+/*
+ * This driver implements access to coreboot's in-memory console
+ * (CBMEM console). For the original implementation, see
+ * <coreboot>/src/lib/cbmem_console.c.
+ */
+
+ .globl console_cbmc_register
+ .globl console_cbmc_putc
+ .globl console_cbmc_flush
+
+ /* -----------------------------------------------
+ * int console_cbmc_register(console_cbmc_t *console,
+ * uintptr_t base)
+ * Registers a new CBMEM console instance. Reads
+ * the size field from the buffer header structure
+ * and stores it in our console_cbmc_t struct, so
+ * that we keep the size in secure memory where we
+ * can trust it. A malicious EL1 could manipulate
+ * the console buffer (including the header), so we
+ * must not trust its contents after boot.
+ * In: x0 - CBMEM console base address
+ * x1 - pointer to empty console_cbmc_t struct
+ * Out: x0 - 1 to indicate success
+ * Clobber list: x0, x1, x2, x7
+ * -----------------------------------------------
+ */
+func console_cbmc_register
+ str x0, [x1, #CONSOLE_T_CBMC_BASE]
+ ldr w2, [x0]
+ str w2, [x1, #CONSOLE_T_CBMC_SIZE]
+ mov x0, x1
+ finish_console_register cbmc
+endfunc console_cbmc_register
+
+ /* -----------------------------------------------
+ * int console_cbmc_puts(int c, console_cbmc_t *console)
+ * Writes a character to the CBMEM console buffer,
+ * including overflow handling of the cursor field.
+ * The character must be preserved in x0.
+ * In: x0 - character to be stored
+ * x1 - pointer to console_cbmc_t struct
+ * Clobber list: x1, x2, x16, x17
+ * -----------------------------------------------
+ */
+func console_cbmc_putc
+ ldr w2, [x1, #CONSOLE_T_CBMC_SIZE]
+ ldr x1, [x1, #CONSOLE_T_CBMC_BASE]
+ add x1, x1, #8 /* keep address of body in x1 */
+
+ ldr w16, [x1, #-4] /* load cursor (one u32 before body) */
+ and w17, w16, #0xf0000000 /* keep flags part in w17 */
+ and w16, w16, #0x0fffffff /* keep actual cursor part in w16 */
+
+ cmp w16, w2 /* sanity check that cursor < size */
+ b.lo putc_within_bounds
+ mov w0, #-1 /* cursor >= size must be malicious */
+ ret /* so return error, don't write char */
+
+putc_within_bounds:
+ strb w0, [x1, w16, uxtw] /* body[cursor] = character */
+ add w16, w16, #1 /* cursor++ */
+ cmp w16, w2 /* if cursor < size... */
+ b.lo putc_write_back /* ...skip overflow handling */
+
+ mov w16, #0 /* on overflow, set cursor back to 0 */
+ orr w17, w17, #(1 << 31) /* and set overflow flag */
+
+putc_write_back:
+ orr w16, w16, w17 /* merge cursor and flags back */
+ str w16, [x1, #-4] /* write back cursor to memory */
+ ret
+endfunc console_cbmc_putc
+
+ /* -----------------------------------------------
+ * int console_cbmc_flush(console_cbmc_t *console)
+ * Flushes the CBMEM console by flushing the
+ * console buffer from the CPU's data cache.
+ * In: x0 - pointer to console_cbmc_t struct
+ * Out: x0 - 0 for success
+ * Clobber list: x0, x1, x2, x3, x5
+ * -----------------------------------------------
+ */
+func console_cbmc_flush
+ mov x5, x30
+ ldr x1, [x0, #CONSOLE_T_CBMC_SIZE]
+ ldr x0, [x0, #CONSOLE_T_CBMC_BASE]
+ add x1, x1, #8 /* add size of console header */
+ bl clean_dcache_range /* (clobbers x2 and x3) */
+ mov x0, #0
+ ret x5
+endfunc console_cbmc_flush