summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.inc27
-rw-r--r--src/console/Kconfig31
-rw-r--r--src/console/console.c4
-rw-r--r--src/drivers/spi/Makefile.inc8
-rw-r--r--src/drivers/spi/flashconsole.c142
-rw-r--r--src/include/console/flash.h45
-rw-r--r--util/cbfstool/default-x86.fmd1
-rw-r--r--util/cbfstool/default.fmd1
8 files changed, 256 insertions, 3 deletions
diff --git a/Makefile.inc b/Makefile.inc
index 1e65228841..99110ed538 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -790,9 +790,19 @@ FMAP_BIOS_SIZE := $(shell echo $(CONFIG_CBFS_SIZE) | tr A-F a-f)
# position and size of flashmap, relative to BIOS_BASE
FMAP_FMAP_BASE := 0
FMAP_FMAP_SIZE := 0x100
+# position, size and entry line of CONSOLE relative to BIOS_BASE, if enabled
+ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
+FMAP_CONSOLE_BASE := $(call int-add, $(FMAP_FMAP_BASE) $(FMAP_FMAP_SIZE))
+FMAP_CONSOLE_SIZE := $(CONFIG_CONSOLE_SPI_FLASH_BUFFER_SIZE)
+FMAP_CONSOLE_ENTRY := CONSOLE@$(FMAP_CONSOLE_BASE) $(FMAP_CONSOLE_SIZE)
+else # ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
+FMAP_CONSOLE_BASE := 0
+FMAP_CONSOLE_SIZE := 0
+FMAP_CONSOLE_ENTRY :=
+endif # ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
# position and size of CBFS, relative to BIOS_BASE
-FMAP_CBFS_BASE := $(FMAP_FMAP_SIZE)
-FMAP_CBFS_SIZE := $(call int-subtract, $(FMAP_BIOS_SIZE) $(FMAP_FMAP_SIZE))
+FMAP_CBFS_BASE := $(call int-add, $(FMAP_CONSOLE_SIZE) $(FMAP_FMAP_SIZE))
+FMAP_CBFS_SIZE := $(call int-subtract, $(FMAP_BIOS_SIZE) $(FMAP_CBFS_BASE))
else # ifeq ($(CONFIG_ARCH_X86),y)
DEFAULT_FLASHMAP:=$(top)/util/cbfstool/default.fmd
# entire flash
@@ -805,8 +815,18 @@ FMAP_BIOS_SIZE := $(CONFIG_CBFS_SIZE)
# position and size of flashmap, relative to BIOS_BASE
FMAP_FMAP_BASE := 0x20000
FMAP_FMAP_SIZE := 0x100
+# position, size and entry line of CONSOLE relative to BIOS_BASE, if enabled
+ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
+FMAP_CONSOLE_BASE := $(call int-add, $(FMAP_FMAP_BASE) $(FMAP_FMAP_SIZE))
+FMAP_CONSOLE_SIZE := $(CONFIG_CONSOLE_SPI_FLASH_BUFFER_SIZE)
+FMAP_CONSOLE_ENTRY := CONSOLE@$(FMAP_CONSOLE_BASE) $(FMAP_CONSOLE_SIZE)
+else # ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
+FMAP_CONSOLE_BASE := 0
+FMAP_CONSOLE_SIZE := 0
+FMAP_CONSOLE_ENTRY :=
+endif # ifeq ($(CONFIG_CONSOLE_SPI_FLASH),y)
# position and size of CBFS, relative to BIOS_BASE
-FMAP_CBFS_BASE := $(call int-add,$(FMAP_FMAP_BASE) $(FMAP_FMAP_SIZE))
+FMAP_CBFS_BASE := $(call int-add,$(FMAP_FMAP_BASE) $(FMAP_FMAP_SIZE) $(FMAP_CONSOLE_SIZE))
FMAP_CBFS_SIZE := $(call int-subtract,$(FMAP_BIOS_SIZE) $(FMAP_CBFS_BASE))
endif # ifeq ($(CONFIG_ARCH_X86),y)
@@ -817,6 +837,7 @@ $(obj)/fmap.fmd: $(top)/Makefile.inc $(DEFAULT_FLASHMAP) $(obj)/config.h
-e "s,##BIOS_SIZE##,$(FMAP_BIOS_SIZE)," \
-e "s,##FMAP_BASE##,$(FMAP_FMAP_BASE)," \
-e "s,##FMAP_SIZE##,$(FMAP_FMAP_SIZE)," \
+ -e "s,##CONSOLE_ENTRY##,$(FMAP_CONSOLE_ENTRY)," \
-e "s,##CBFS_BASE##,$(FMAP_CBFS_BASE)," \
-e "s,##CBFS_SIZE##,$(FMAP_CBFS_SIZE)," \
$(DEFAULT_FLASHMAP) > $@.tmp
diff --git a/src/console/Kconfig b/src/console/Kconfig
index caf91ab252..c0e4a8c8b0 100644
--- a/src/console/Kconfig
+++ b/src/console/Kconfig
@@ -233,6 +233,37 @@ config CONSOLE_CBMEM_DUMP_TO_UART
endif
+config CONSOLE_SPI_FLASH
+ bool "SPI Flash console output"
+ default n
+ select BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY if !COMMON_CBFS_SPI_WRAPPER
+ help
+ Send coreboot debug output to the SPI Flash in the FMAP CONSOLE area
+
+ 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).
+
+ The 'CONSOLE' area can be extracted from the FMAP with :
+ cbfstool rom.bin read -r CONSOLE -f console.log
+
+config CONSOLE_SPI_FLASH_BUFFER_SIZE
+ hex "Room allocated for console output in FMAP"
+ default 0x20000
+ depends on CONSOLE_SPI_FLASH
+ help
+ Space allocated for console output storage in FMAP. The default
+ value (128K or 0x20000 bytes) is large enough to accommodate
+ even the BIOS_SPEW level.
+
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 7b0dfc2fb1..877c8dc960 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 @@ void console_hw_init(void)
__ne2k_init();
__usbdebug_init();
__spiconsole_init();
+ __flashconsole_init();
}
void console_tx_byte(unsigned char byte)
@@ -53,6 +55,7 @@ void console_tx_byte(unsigned char byte)
__ne2k_tx_byte(byte);
__usb_tx_byte(byte);
__spiconsole_tx_byte(byte);
+ __flashconsole_tx_byte(byte);
}
void console_tx_flush(void)
@@ -60,6 +63,7 @@ void console_tx_flush(void)
__uart_tx_flush();
__ne2k_tx_flush();
__usb_tx_flush();
+ __flashconsole_tx_flush();
}
void console_write_line(uint8_t *buffer, size_t number_of_bytes)
diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc
index c1bf307cc5..c594d4e74c 100644
--- a/src/drivers/spi/Makefile.inc
+++ b/src/drivers/spi/Makefile.inc
@@ -7,6 +7,14 @@ ramstage-y += spiconsole.c
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
+
+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 0000000000..e73af22951
--- /dev/null
+++ b/src/drivers/spi/flashconsole.c
@@ -0,0 +1,142 @@
+/*
+ * 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 <fmap.h>
+#include <console/console.h>
+#include <console/flash.h>
+#include <string.h>
+
+#define LINE_BUFFER_SIZE 128
+#define READ_BUFFER_SIZE 0x100
+
+static const struct region_device *g_rdev_ptr CAR_GLOBAL;
+static struct region_device g_rdev CAR_GLOBAL;
+static uint8_t g_line_buffer[LINE_BUFFER_SIZE] CAR_GLOBAL;
+static size_t g_offset CAR_GLOBAL;
+static size_t g_line_offset CAR_GLOBAL;
+
+void flashconsole_init(void)
+{
+ struct region_device *rdev = car_get_var_ptr(&g_rdev);
+ uint8_t buffer[READ_BUFFER_SIZE];
+ size_t size;
+ size_t offset = 0;
+ size_t len = READ_BUFFER_SIZE;
+ size_t i;
+
+ if (fmap_locate_area_as_rdev_rw("CONSOLE", rdev)) {
+ printk(BIOS_INFO, "Can't find 'CONSOLE' area in FMAP\n");
+ return;
+ }
+ size = region_device_sz(rdev);
+
+ /*
+ * 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 < size; ) {
+ // Fill the buffer on first iteration
+ if (i == 0) {
+ len = min(READ_BUFFER_SIZE, size - offset);
+ if (rdev_readat(rdev, buffer, offset, len) != len)
+ return;
+ }
+ if (buffer[i] == 0xff) {
+ offset += i;
+ break;
+ }
+ // If we're done, repeat the process for the next sector
+ if (++i == READ_BUFFER_SIZE) {
+ offset += len;
+ i = 0;
+ }
+ }
+ // Make sure there is still space left on the console
+ if (offset >= size) {
+ printk(BIOS_INFO, "No space left on 'console' region in SPI flash\n");
+ return;
+ }
+
+ car_set_var(g_offset, offset);
+ /* Set g_rdev_ptr last so tx_byte doesn't get executed early */
+ car_set_var(g_rdev_ptr, rdev);
+}
+
+void flashconsole_tx_byte(unsigned char c)
+{
+ const struct region_device *rdev = car_get_var(g_rdev_ptr);
+ uint8_t *line_buffer;
+ size_t offset;
+ size_t len;
+ size_t region_size;
+
+ if (!rdev)
+ return;
+
+ line_buffer = car_get_var_ptr(g_line_buffer);
+ offset = car_get_var(g_offset);
+ len = car_get_var(g_line_offset);
+ region_size = region_device_sz(rdev);
+
+ line_buffer[len++] = c;
+ car_set_var(g_line_offset, len);
+
+ if (len >= LINE_BUFFER_SIZE ||
+ offset + len >= region_size || c == '\n') {
+ flashconsole_tx_flush();
+ }
+}
+
+void flashconsole_tx_flush(void)
+{
+ const struct region_device *rdev = car_get_var(g_rdev_ptr);
+ uint8_t *line_buffer = car_get_var_ptr(g_line_buffer);
+ size_t offset = car_get_var(g_offset);
+ size_t len = car_get_var(g_line_offset);
+ size_t region_size;
+
+ if (!rdev)
+ return;
+
+ /* 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_ptr, NULL);
+
+ region_size = region_device_sz(rdev);
+ if (offset + len >= region_size)
+ len = region_size - offset;
+
+ if (rdev_writeat(rdev, line_buffer, offset, len) != len)
+ rdev = NULL;
+
+ // If the region is full, stop future write attempts
+ if (offset + len >= region_size)
+ rdev = NULL;
+
+ car_set_var(g_offset, offset + len);
+ car_set_var(g_line_offset, 0);
+
+ car_set_var(g_rdev_ptr, rdev);
+}
diff --git a/src/include/console/flash.h b/src/include/console/flash.h
new file mode 100644
index 0000000000..07bc724b19
--- /dev/null
+++ b/src/include/console/flash.h
@@ -0,0 +1,45 @@
+/*
+ * 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);
+void flashconsole_tx_flush(void);
+
+#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);
+}
+static inline void __flashconsole_tx_flush(void)
+{
+ flashconsole_tx_flush();
+}
+#else
+static inline void __flashconsole_init(void) {}
+static inline void __flashconsole_tx_byte(u8 data) {}
+static inline void __flashconsole_tx_flush(void) {}
+#endif /* __CONSOLE_FLASH_ENABLE__ */
+
+
+#endif /* CONSOLE_FLASH_H */
diff --git a/util/cbfstool/default-x86.fmd b/util/cbfstool/default-x86.fmd
index f344ab2086..1b6cfc8ba6 100644
--- a/util/cbfstool/default-x86.fmd
+++ b/util/cbfstool/default-x86.fmd
@@ -10,6 +10,7 @@
FLASH@##ROM_BASE## ##ROM_SIZE## {
BIOS@##BIOS_BASE## ##BIOS_SIZE## {
FMAP@##FMAP_BASE## ##FMAP_SIZE##
+ ##CONSOLE_ENTRY##
COREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##
}
}
diff --git a/util/cbfstool/default.fmd b/util/cbfstool/default.fmd
index 32ddfa4074..50b9bf0bd1 100644
--- a/util/cbfstool/default.fmd
+++ b/util/cbfstool/default.fmd
@@ -13,6 +13,7 @@ FLASH@##ROM_BASE## ##ROM_SIZE## {
BIOS@##BIOS_BASE## ##BIOS_SIZE## {
BOOTBLOCK 128K
FMAP@##FMAP_BASE## ##FMAP_SIZE##
+ ##CONSOLE_ENTRY##
COREBOOT(CBFS)@##CBFS_BASE## ##CBFS_SIZE##
}
}