[coreboot-gerrit] Change in coreboot[master]: console/cbfsconsole: Adding a spi flash console for debugging

Youness Alaoui (Code Review) gerrit at coreboot.org
Wed May 24 01:12:27 CEST 2017


Youness Alaoui has uploaded a new change for review. ( https://review.coreboot.org/19849 )

Change subject: console/cbfsconsole: Adding a spi flash console for debugging
......................................................................

console/cbfsconsole: Adding a spi flash console for debugging

If CONSOLE_SPI_FLASH config is enabled, we can write the cbmem
messages to the 'console' region in CBFS which allows
us to grab the log when we read the flash.

This is useful when you don't have usb debugging, and
UART lines are hard to find. Since a failure to boot would
require a hardware flasher anyways, we can get the log
at the same time.

This feature should only be used when no alternative is
found and only when we can't boot the system, because
excessive writes to the flash is not recommended.

This has been tested on purism/librem13 v2 and librem 15 v3 which
run skylake hardware. It has not been tested on other archs or with
a driver other than the fast_spi.

The Kconfig help mentions support for writing to an fmap area
but this isn't supported yet.

Change-Id: I74a297b94f6881d8c27cbe5168f161d8331c3df3
Signed-off-by: Youness Alaoui <youness.alaoui at puri.sm>
---
M src/console/Kconfig
M src/console/console.c
M src/drivers/spi/Makefile.inc
A src/drivers/spi/flashconsole.c
A src/include/console/flash.h
5 files changed, 254 insertions(+), 0 deletions(-)


  git pull ssh://review.coreboot.org:29418/coreboot refs/changes/49/19849/1

diff --git a/src/console/Kconfig b/src/console/Kconfig
index caf91ab..781ccb5 100644
--- a/src/console/Kconfig
+++ b/src/console/Kconfig
@@ -233,6 +233,46 @@
 
 endif
 
+config CONSOLE_SPI_FLASH
+	bool "SPI Flash console output"
+	default n
+	select BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY
+	help
+	  Send coreboot debug output to the SPI Flash in either the FMAP
+	  CONSOLE area or the CBFS 'console' region.
+
+	  This option can cause premature wear on the SPI flash and should not
+	  be used as a normal means of debugging. It is only to be enabled and
+	  used when porting a new motherboard which has no other console
+	  available (no UART, no POST, no cbmem access(non bootable)). Since
+	  a non bootable machine will require the use of an external SPI Flash
+	  programmer, the developer can grab the console log at the same time.
+
+	  The flash console will not be erased on reboot, so once it is full,
+	  the flashconsole driver will stop writing to it. This is to avoid
+	  wear on the flash, and to avoid erasing sectors (which may freeze
+	  the SPI controller on skylake).
+
+	  If a 'CONSOLE' area is defined in a custom FMAP fmd file, the driver
+	  will find it and use it, otherwise, it will look for a 'console'
+	  region in the CBFS.
+
+if CONSOLE_SPI_FLASH
+
+config CONSOLE_CBFS_BUFFER_SIZE
+	hex "Room allocated for console output in CBFS"
+	default 0x20000
+	help
+	  Space allocated for console output storage in CBFS. The default
+	  value (128K or 0x20000 bytes) is large enough to accommodate
+	  even the BIOS_SPEW level.
+	  If a custom FMAP is defined with a 'CONSOLE' area, then the CBFS
+	  region will never be used and this value should be set to 0.
+	  The 'console' region will always be added to CBFS if this option is
+	  higher than 0, even if it will not be used (if the fmd already
+	  contains the 'CONSOLE' area).
+endif
+
 config CONSOLE_QEMU_DEBUGCON
 	bool "QEMU debug console output"
 	depends on BOARD_EMULATION_QEMU_X86
diff --git a/src/console/console.c b/src/console/console.c
index 7b0dfc2..2b7f99d 100644
--- a/src/console/console.c
+++ b/src/console/console.c
@@ -21,6 +21,7 @@
 #include <console/uart.h>
 #include <console/usb.h>
 #include <console/spi.h>
+#include <console/flash.h>
 #include <rules.h>
 
 void console_hw_init(void)
@@ -33,6 +34,7 @@
 	__ne2k_init();
 	__usbdebug_init();
 	__spiconsole_init();
+	__flashconsole_init();
 }
 
 void console_tx_byte(unsigned char byte)
@@ -53,6 +55,7 @@
 	__ne2k_tx_byte(byte);
 	__usb_tx_byte(byte);
 	__spiconsole_tx_byte(byte);
+	__flashconsole_tx_byte(byte);
 }
 
 void console_tx_flush(void)
diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc
index c1bf307..2573af0 100644
--- a/src/drivers/spi/Makefile.inc
+++ b/src/drivers/spi/Makefile.inc
@@ -7,6 +7,28 @@
 smm-$(CONFIG_DEBUG_SMI) += spiconsole.c
 endif
 
+ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
+bootblock-y += flashconsole.c
+romstage-y += flashconsole.c
+ramstage-y += flashconsole.c
+smm-$(CONFIG_DEBUG_SMI) += flashconsole.c
+
+__cbfsconsole_size = $(shell printf "%d" $(CONFIG_CONSOLE_CBFS_BUFFER_SIZE))
+
+ifneq ($(__cbfsconsole_size),0)
+$(obj)/console: $(obj)/config.h
+	dd if=/dev/zero count=1 \
+	bs=$(__cbfsconsole_size) \
+	| tr '\000' '\377' > $@
+
+cbfs-files-y += console
+console-file := $(obj)/console
+console-type := raw
+console-align := 4096
+endif
+
+endif
+
 bootblock-y += spi-generic.c
 bootblock-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
 bootblock-$(CONFIG_SPI_FLASH) += spi_flash.c
diff --git a/src/drivers/spi/flashconsole.c b/src/drivers/spi/flashconsole.c
new file mode 100644
index 0000000..bd918c1
--- /dev/null
+++ b/src/drivers/spi/flashconsole.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/early_variables.h>
+#include <region.h>
+#include <boot_device.h>
+#include <cbfs.h>
+#include <console/flash.h>
+#include <string.h>
+#include <assert.h>
+#include <spi_flash.h>
+
+#define LINE_BUFFER_SIZE 0x1000
+
+static const struct region_device *g_rdev CAR_GLOBAL;
+static uint8_t g_line_buffer[LINE_BUFFER_SIZE] CAR_GLOBAL;
+static size_t g_region_offset CAR_GLOBAL;
+static size_t g_region_size CAR_GLOBAL;
+static uint32_t g_offset CAR_GLOBAL;
+
+void flashconsole_init(void)
+{
+	struct cbfsf file;
+
+	car_set_var(g_rdev, NULL);
+	car_set_var(g_offset, 0);
+
+	cbfs_prepare_program_locate();
+	if (cbfs_boot_locate(&file, "console", NULL) == 0) {
+		struct region_device cbfs_region;
+		const struct region_device *rdev;
+		uint8_t *line_buffer = car_get_var_ptr(g_line_buffer);
+		uint32_t cbfs_offset;
+		uint32_t cbfs_size;
+		uint32_t offset = 0;
+		int i;
+		int len = LINE_BUFFER_SIZE;
+
+		cbfs_file_data(&cbfs_region, &file);
+		cbfs_offset = region_device_offset(&cbfs_region);
+		cbfs_size = region_device_sz(&cbfs_region);
+
+		boot_device_init();
+		rdev = boot_device_rw();
+
+		/*
+		 * We need to check the region until we find a 0xff indicating
+		 * the end of a previous log write.
+		 * We can't erase the region because one stage would erase the
+		 * data from the previous stage. Also, it looks like doing an
+		 * erase could completely freeze the SPI controller and then
+		 * we can't write anything anymore (apparently might happen if
+		 * the sector is already erased, so we would need to read
+		 * anyways to check if it's all 0xff).
+		 */
+		for (i = 0; i < len && offset < cbfs_size; ) {
+			// Fill the buffer on first iteration
+			if (i == 0) {
+				len = min(LINE_BUFFER_SIZE, cbfs_size - offset);
+				rdev_readat(rdev, line_buffer,
+					cbfs_offset + offset, len);
+			}
+			if (line_buffer[i] == 0xff) {
+				offset += i;
+				break;
+			}
+			// If we're done, repeat the process for the next sector
+			if (++i == LINE_BUFFER_SIZE) {
+				offset += len;
+				i = 0;
+			}
+		}
+		// Make sure there is still space left on the console
+		if (offset < cbfs_size) {
+			// Now we can enable tx_byte
+			car_set_var(g_region_offset, cbfs_offset);
+			car_set_var(g_region_size, cbfs_size);
+			car_set_var(g_offset, offset);
+			memset(line_buffer, 0, LINE_BUFFER_SIZE);
+			// Set g_rdev last so tx_byte doesn't get executed early
+			car_set_var(g_rdev, rdev);
+		} else {
+			printk(BIOS_INFO, "No space left on 'console' region in CBFS.");
+		}
+	} else {
+		printk(BIOS_INFO, "Can't find 'console' region in CBFS.");
+	}
+
+}
+
+void flashconsole_tx_byte(unsigned char c)
+{
+	const struct region_device *rdev = car_get_var(g_rdev);
+
+	if (rdev) {
+		uint8_t *line_buffer = car_get_var_ptr(g_line_buffer);
+		uint32_t offset = car_get_var(g_offset);
+		uint32_t region_size = car_get_var(g_region_size);
+		int i;
+		uint32_t len = LINE_BUFFER_SIZE - 1;
+
+		/* Prevent any recursive loops in case the spi flash driver
+		 * calls printk (in case of transaction timeout or
+		 * any other error while writing) */
+		car_set_var(g_rdev, NULL);
+
+		/* Do line-buffering on the writes to avoid doing an SPI write
+		 * on every byte */
+		for (i = 0; i < LINE_BUFFER_SIZE - 1; i++) {
+			if (line_buffer[i] == 0) {
+				line_buffer[i] = c;
+				line_buffer[i+1] = 0;
+				len = i+1;
+				break;
+			}
+		}
+		if (len >= LINE_BUFFER_SIZE - 1 ||
+			offset + len >= region_size || c == '\n') {
+			uint32_t region_offset = car_get_var(g_region_offset);
+
+			// We crop the rest of the line if the region is full
+			if (offset + len >= region_size)
+				len = region_size - offset;
+
+			rdev_writeat(rdev, line_buffer, region_offset + offset,
+				len);
+
+			// If the region is full, stop future write attempts
+			if (offset + len >= region_size)
+				rdev = NULL;
+
+			car_set_var(g_offset, offset + len);
+			line_buffer[0] = 0;
+		}
+		car_set_var(g_rdev, rdev);
+	}
+
+}
diff --git a/src/include/console/flash.h b/src/include/console/flash.h
new file mode 100644
index 0000000..fa4de00
--- /dev/null
+++ b/src/include/console/flash.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CONSOLE_FLASH_H
+#define CONSOLE_FLASH_H 1
+
+#include <rules.h>
+#include <stdint.h>
+
+void flashconsole_init(void);
+void flashconsole_tx_byte(unsigned char c);
+
+#define __CONSOLE_FLASH_ENABLE__	IS_ENABLED(CONFIG_CONSOLE_SPI_FLASH)
+
+#if __CONSOLE_FLASH_ENABLE__
+static inline void __flashconsole_init(void)	{ flashconsole_init(); }
+static inline void __flashconsole_tx_byte(u8 data)
+{
+	flashconsole_tx_byte(data);
+}
+#else
+static inline void __flashconsole_init(void)	{}
+static inline void __flashconsole_tx_byte(u8 data)	{}
+#endif /* __CONSOLE_FLASH_ENABLE__ */
+
+
+#endif /* CONSOLE_FLASH_H */

-- 
To view, visit https://review.coreboot.org/19849
To unsubscribe, visit https://review.coreboot.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I74a297b94f6881d8c27cbe5168f161d8331c3df3
Gerrit-PatchSet: 1
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Owner: Youness Alaoui <snifikino at gmail.com>



More information about the coreboot-gerrit mailing list