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