1/*
2 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <asm_macros.S>
8#include <console_macros.S>
9#include <drivers/coreboot/cbmem_console.h>
10
11/*
12 * This driver implements access to coreboot's in-memory console
13 * (CBMEM console). For the original implementation, see
14 * <coreboot>/src/lib/cbmem_console.c.
15 */
16
17	.globl console_cbmc_register
18	.globl console_cbmc_putc
19	.globl console_cbmc_flush
20
21	/* -----------------------------------------------
22	 * int console_cbmc_register(uintptr_t base,
23	 *                           console_cbmc_t *console);
24	 * Registers a new CBMEM console instance. Reads
25	 * the size field from the buffer header structure
26	 * and stores it in our console_cbmc_t struct, so
27	 * that we keep the size in secure memory where we
28	 * can trust it. A malicious EL1 could manipulate
29	 * the console buffer (including the header), so we
30	 * must not trust its contents after boot.
31	 * In:  x0 - CBMEM console base address
32	 *      x1 - pointer to empty console_cbmc_t struct
33	 * Out: x0 - 1 to indicate success
34	 * Clobber list: x0, x1, x2, x7
35	 * -----------------------------------------------
36	 */
37func console_cbmc_register
38	str	x0, [x1, #CONSOLE_T_BASE]
39	ldr	w2, [x0]
40	str	w2, [x1, #CONSOLE_T_CBMC_SIZE]
41	mov	x0, x1
42	finish_console_register cbmc putc=1, flush=1
43endfunc console_cbmc_register
44
45	/* -----------------------------------------------
46	 * int console_cbmc_puts(int c, console_cbmc_t *console)
47	 * Writes a character to the CBMEM console buffer,
48	 * including overflow handling of the cursor field.
49	 * The character must be preserved in x0.
50	 * In: x0 - character to be stored
51	 *     x1 - pointer to console_cbmc_t struct
52	 * Clobber list: x1, x2, x16, x17
53	 * -----------------------------------------------
54	 */
55func console_cbmc_putc
56	ldr	w2, [x1, #CONSOLE_T_CBMC_SIZE]
57	ldr	x1, [x1, #CONSOLE_T_BASE]
58	add	x1, x1, #8		/* keep address of body in x1 */
59
60	ldr	w16, [x1, #-4]		/* load cursor (one u32 before body) */
61	and	w17, w16, #0xf0000000	/* keep flags part in w17 */
62	and	w16, w16, #0x0fffffff	/* keep actual cursor part in w16 */
63
64	cmp	w16, w2			/* sanity check that cursor < size */
65	b.lo	putc_within_bounds
66	mov	w0, #-1			/* cursor >= size must be malicious */
67	ret				/* so return error, don't write char */
68
69putc_within_bounds:
70	strb	w0, [x1, w16, uxtw]	/* body[cursor] = character */
71	add	w16, w16, #1		/* cursor++ */
72	cmp	w16, w2			/* if cursor < size... */
73	b.lo	putc_write_back		/* ...skip overflow handling */
74
75	mov	w16, #0			/* on overflow, set cursor back to 0 */
76	orr	w17, w17, #(1 << 31)	/* and set overflow flag */
77
78putc_write_back:
79	orr	w16, w16, w17		/* merge cursor and flags back */
80	str	w16, [x1, #-4]		/* write back cursor to memory */
81	ret
82endfunc	console_cbmc_putc
83
84	/* -----------------------------------------------
85	 * void console_cbmc_flush(console_cbmc_t *console)
86	 * Flushes the CBMEM console by flushing the
87	 * console buffer from the CPU's data cache.
88	 * In:  x0 - pointer to console_cbmc_t struct
89	 * Out: void
90	 * Clobber list: x0, x1, x2, x3
91	 * -----------------------------------------------
92	 */
93func console_cbmc_flush
94	ldr	x1, [x0, #CONSOLE_T_CBMC_SIZE]
95	ldr	x0, [x0, #CONSOLE_T_BASE]
96	add	x1, x1, #8		/* add size of console header */
97	b	clean_dcache_range	/* (clobbers x2 and x3) */
98endfunc console_cbmc_flush
99