summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/coreboot/cbmem_console/aarch64/cbmem_console.S101
-rw-r--r--include/drivers/coreboot/cbmem_console.h27
-rw-r--r--lib/coreboot/coreboot.mk4
-rw-r--r--lib/coreboot/coreboot_table.c34
4 files changed, 166 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
diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h
new file mode 100644
index 00000000..4fca36f6
--- /dev/null
+++ b/include/drivers/coreboot/cbmem_console.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CBMEM_CONSOLE_H__
+#define __CBMEM_CONSOLE_H__
+
+#include <console.h>
+
+#define CONSOLE_T_CBMC_BASE CONSOLE_T_DRVDATA
+#define CONSOLE_T_CBMC_SIZE (CONSOLE_T_DRVDATA + REGSZ)
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+ console_t console;
+ uintptr_t base;
+ uint32_t size;
+} console_cbmc_t;
+
+int console_cbmc_register(uintptr_t base, console_cbmc_t *console);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __CBMEM_CONSOLE_H__ */
diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk
index 0cd103f2..bbaa3329 100644
--- a/lib/coreboot/coreboot.mk
+++ b/lib/coreboot/coreboot.mk
@@ -17,4 +17,8 @@ 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
index 76e5d3b7..64f8879e 100644
--- a/lib/coreboot/coreboot_table.c
+++ b/lib/coreboot/coreboot_table.c
@@ -4,10 +4,13 @@
* 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
@@ -26,6 +29,7 @@ typedef struct {
typedef enum {
CB_TAG_SERIAL = 0xf,
+ CB_TAG_CBMEM_CONSOLE = 0x17,
} cb_tag_t;
typedef struct {
@@ -33,6 +37,7 @@ typedef struct {
uint32_t size;
union {
coreboot_serial_t serial;
+ uint64_t uint64;
};
} cb_entry_t;
@@ -53,6 +58,32 @@ static uint32_t read_le32(uint32_t *p)
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)
{
@@ -79,6 +110,9 @@ void coreboot_table_setup(void *base)
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;