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