[coreboot-gerrit] New patch to review for filo: aabf16e Add flashupdate command

Patrick Georgi (patrick@georgi-clan.de) gerrit at coreboot.org
Fri Jun 13 13:47:21 CEST 2014


Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5988

-gerrit

commit aabf16e761d8c6eb2c25a1aceffa336356492c0d
Author: Patrick Georgi <patrick.georgi at secunet.com>
Date:   Tue Jul 19 16:40:06 2011 +0200

    Add flashupdate command
    
    This command allows the user to load a coreboot image, configure its
    cmos.default file and write it to flash, all from FILO.
    
    Change-Id: Ia011deb64bcf75aebe8b67554ad9d9738d90fe59
---
 Config.in                     |  15 ++-
 Makefile                      |   1 +
 flashupdate/Makefile.inc      |  29 +++++
 flashupdate/flashrom-bridge.c |  73 +++++++++++
 flashupdate/flashupdate.c     | 277 ++++++++++++++++++++++++++++++++++++++++++
 main/grub/builtins.c          |  19 ++-
 x86/ldscript                  |   6 +-
 7 files changed, 413 insertions(+), 7 deletions(-)

diff --git a/Config.in b/Config.in
index cc48bd3..d9f977a 100644
--- a/Config.in
+++ b/Config.in
@@ -189,8 +189,7 @@ config FLASHROM_LOCKDOWN
 	default n
 	help
 	  Enable system flash memory write protections and lock them down prior
-	  starting the kernel. Flash memory lockdown can be disabled per boot
-	  entry with the new command 'flashrom_unlock'.
+	  starting the kernel.
 
 	  NOTE: Only supported on selected hardware:
 
@@ -199,6 +198,18 @@ config FLASHROM_LOCKDOWN
 	        o Intel Cougar Point / Panther Point PCH (FWH + SPI)
 	        o AMD SB600 (SPI by locking the flash chip itself)
 
+config FLASHROM_UNLOCK
+	bool "Provide flashrom_unlock command"
+	default n
+	depends on FLASHROM_LOCKDOWN
+	help
+	  FlashROM lockdown can be disabled per boot entry with the new
+	  command 'flashrom_unlock'.
+
+config FLASHUPDATE
+	bool "add flashrom utility to FILO"
+	default y
+
 endmenu
 
 menu "Filesystems"
diff --git a/Makefile b/Makefile
index 46010b3..570bd87 100644
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@ CFLAGS += $(call cc-option, -fno-stack-protector,)
 
 LIBS := $(LIBPAYLOAD) $(LIBGCC)
 
+SUBDIRS-$(CONFIG_USE_GRUB) += flashupdate/
 SUBDIRS-y += main/ fs/ drivers/
 SUBDIRS-y += $(ARCHDIR-y)/
 
diff --git a/flashupdate/Makefile.inc b/flashupdate/Makefile.inc
new file mode 100644
index 0000000..319add3
--- /dev/null
+++ b/flashupdate/Makefile.inc
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2011 secunet AG
+#
+# 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; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LIBFLASHROM_PREFIX ?= $(obj)/libflashrom
+LIBFLASHROM = $(LIBFLASHROM_PREFIX)/lib/libflashrom.a
+INCFLASHROM = $(LIBFLASHROM_PREFIX)/include
+
+ifeq ($(CONFIG_FLASHUPDATE),y)
+CPPFLAGS += -I$(INCFLASHROM)
+LIBS += $(LIBFLASHROM)
+endif
+
+TARGETS-$(CONFIG_FLASHUPDATE) += flashupdate/flashupdate.o
+TARGETS-$(CONFIG_FLASHUPDATE) += flashupdate/flashrom-bridge.o
diff --git a/flashupdate/flashrom-bridge.c b/flashupdate/flashrom-bridge.c
new file mode 100644
index 0000000..0940389
--- /dev/null
+++ b/flashupdate/flashrom-bridge.c
@@ -0,0 +1,73 @@
+#include <stdarg.h>
+#include <string.h>
+
+#include "flashchips.h"
+#include "flash.h"
+#include "programmer.h"
+
+int new_rom_size;
+void *new_rom_data;
+
+int old_rom_size;
+void *old_rom_data;
+
+// for flashrom
+int print(int type, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+int print(int type, const char *fmt, ...)
+{
+#ifdef DEBUG
+	if (type > MSG_INFO) return 0;
+	int ret;
+	va_list args;
+	va_start(args, fmt);
+	ret = vprintf(fmt, args);
+	va_end(args);
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+/* returned memory must be freed by caller */
+char *flashbuses_to_text(enum chipbustype bustype)
+{
+	return strdup("Unknown");
+}
+
+int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename)
+{
+	// we need at least enough space for our image.
+	if (size < new_rom_size)
+		return 1;
+
+	// top-align our image into the chip
+	memcpy(buf + size - new_rom_size, new_rom_data, new_rom_size);
+
+	return 0;
+}
+
+int read_flash_to_file(struct flashctx *flash, const char *filename)
+{
+	int ret = 0;
+	unsigned long size = flash->total_size * 1024;
+	if (size > old_rom_size) {
+		msg_cerr("old rom buffer not large enough for flash\n");
+		ret = 1;
+		goto out_free;
+	}
+
+	if (!flash->read) {
+		msg_cerr("No read function available for this flash chip.\n");
+		ret = 1;
+		goto out_free;
+	}
+	if (flash->read(flash, old_rom_data, 0, size)) {
+		msg_cerr("Read operation failed!\n");
+		ret = 1;
+		goto out_free;
+	}
+
+out_free:
+	return ret;
+}
+
diff --git a/flashupdate/flashupdate.c b/flashupdate/flashupdate.c
new file mode 100644
index 0000000..c0f337d
--- /dev/null
+++ b/flashupdate/flashupdate.c
@@ -0,0 +1,277 @@
+#include <stdlib.h>
+#include <getopt.h>
+#include <libpayload.h>
+#include <coreboot_tables.h>
+#include <cbfs.h>
+#include <grub/shared.h>
+#include <fs.h>
+#include <pci/pci.h>
+
+/* flashrom defines */
+#define CONFIG_INTERNAL 1
+#include "flashchips.h"
+#include "flash.h"
+#include "programmer.h"
+
+extern int new_rom_size;
+extern void *new_rom_data;
+
+struct flashctx flashchip;
+
+static void beep_success()
+{
+	int i;
+	for (i = 0; i < 5; i++) {
+		speaker_tone(440, 200); mdelay(300);
+		speaker_tone(660, 200); mdelay(300);
+		speaker_tone(880, 200); mdelay(300);
+		mdelay(3*1000);
+	}
+}
+
+static void beep_fail()
+{
+	int i;
+	for (i = 0; i < 5; i++) {
+		speaker_tone(1200, 200); mdelay(300);
+		speaker_tone( 660, 200); mdelay(300);
+		mdelay(3*1000);
+	}
+}
+
+static int init_flash(const char* flashtype)
+{
+	int j;
+	verbose++;
+	if (programmer_init(PROGRAMMER_INTERNAL, NULL)) {
+		grub_printf("Could not initialize programmer\n");
+		return -1;
+	}
+	for (j = 0; j < registered_programmer_count; j++) {
+		int current_chip = -1;
+		do {
+			current_chip = probe_flash(&registered_programmers[j], ++current_chip, &flashchip, 0);
+			if ((current_chip != -1) && ((flashtype == NULL) || (strcasecmp(flashchip.name, flashtype) == 0))) {
+				return 0;
+			}
+		} while (current_chip != -1);
+	}
+
+	grub_printf("Could not find flash chip\n");
+	return -1;
+}
+
+static int write_flash(void *imgdata, int size)
+{
+	return doit(&flashchip, 1, imgdata, 0, 1, 0, 1);
+}
+
+static int test_id_section(void *romarea, unsigned int romsize, int offset, char **vendor, char **model, char **version)
+{
+	/* data[-1]: romsize
+	   data[-2]: offset top-of-rom to board model
+	   data[-3]: offset top-of-rom to board vendor
+	   data[-4]: offset top-of-rom to build version */
+	unsigned int *data = romarea+romsize-offset;
+	*version = romarea+romsize-data[-4];
+	*vendor = romarea+romsize-data[-3];
+	*model = romarea+romsize-data[-2];
+	/* Assume that data[-1] matches filesize, and that vendor and model are laid out without extra space.
+           DO NOT assume that model aligns to the offsets, there may be future additions. */
+	return ((data[-1] == romsize) && (*vendor+strnlen(*vendor, data[-2])+1 == *model));
+}
+
+int flashupdate_func(char *arg, int flags)
+{
+	int result = -1;
+	int force = 0;
+	char *chiptype = NULL;
+	char *vendor = NULL;
+	char *board = NULL;
+	char *region = NULL;
+
+	char **argv;
+	int argc = to_argc_argv(arg, &argv);
+
+	new_rom_data = NULL;
+
+	char opt;
+	optreset = optind = 1;
+	while ((opt = getopt(argc, argv, "fc:v:b:i:")) != -1) {
+		switch (opt) {
+			case 'f':
+				force = 1;
+				break;
+			case 'c':
+				chiptype = optarg;
+				break;
+			case 'v':
+				vendor = optarg;
+				break;
+			case 'b':
+				board = optarg;
+				break;
+			case 'i':
+				region = optarg;
+				break;
+			default:
+				grub_printf("unsupported option -%c.\n", opt);
+				goto out;
+				break;
+		}
+	}
+
+	if (optind >= argc) {
+		grub_printf("No filename specified.\n");
+		goto out;
+	}
+	const char *filename = argv[optind];
+
+	if (vendor && board &&
+		((strcmp(vendor, cb_mb_vendor_string(lib_sysinfo.mainboard)) != 0) ||
+		(strcmp(board, cb_mb_part_string(lib_sysinfo.mainboard)) != 0))) {
+		/* since flashupdate semantics is: iff board matches, write flash;
+		   it's a success not to flash on another board. */
+		result = 0;
+		goto out;
+	}
+
+	if (region) {
+		register_include_arg(region);
+		layout_use_ifd();
+	}
+
+	/* Step 0: Init programmer/flash to find out if we _can_ flash (we should) */
+	if (init_flash(chiptype) == -1) {
+		grub_printf("Could not initialize flash programmer.\n");
+		goto out;
+	}
+
+	/* Step 1: read requested image file */
+	if (!file_open(filename)) {
+		grub_printf("Could not open file '%s'\n", filename);
+		goto out;
+	}
+
+	/* 16K of extra space, since we don't have feof() */
+	new_rom_size = flashchip.total_size * 1024 + 16384;
+	new_rom_data = malloc(new_rom_size);
+	if (new_rom_data == NULL) {
+		grub_printf("Could not allocate memory.\n");
+		goto out;
+	}
+	void *readbuf = new_rom_data;
+	int len;
+	grub_printf("Loading image file... ");
+	while ((len = file_read(readbuf, 16384)) != 0) {
+		readbuf += len;
+		/* We can abort if we cut into the last 16K:
+		 * it's more than the flash is able to carry
+		 */
+		if (readbuf - new_rom_data > new_rom_size - 16384) {
+			file_close();
+			grub_printf("File too large for flash\n");
+			goto out;
+		}
+	}
+	new_rom_size = readbuf - new_rom_data;
+	file_close();
+	grub_printf("done\n");
+
+	/* retarget all CBFS accesses to new image */
+	setup_cbfs_from_ram(new_rom_data, new_rom_size);
+
+	/* Step 2: Check Board IDs (that we work on the right image) */
+	const char *cur_version = lib_sysinfo.cb_version;
+	const char *cur_vendor = cb_mb_vendor_string(lib_sysinfo.mainboard);
+	const char *cur_board = cb_mb_part_string(lib_sysinfo.mainboard);
+
+	/* Step 2a: check if this is a coreboot image by looking for a CBFS master header */
+	if (get_cbfs_header() != 0xffffffff) {
+		/* Step 2b: look for .id section in new ROM */
+		/* There are currently two locations where .id can reside: top-0x10 and top-0x80. There's
+		   no indicator which one is used in any given image, though it should be stable on any given
+		   board. As a heuristic, we can check if the data is sane at each location. */
+		char *new_vendor;
+		char *new_board;
+		char *new_version;
+		if (!test_id_section(new_rom_data, new_rom_size, 0x10, &new_vendor, &new_board, &new_version))
+			if (!test_id_section(new_rom_data, new_rom_size, 0x80, &new_vendor, &new_board, &new_version)) {
+				grub_printf("Could not detect if file supports this system.\n");
+				goto out;
+		}
+		if ((strcmp(cur_vendor, new_vendor) != 0) || (strcmp(cur_board, new_board) != 0)) {
+			grub_printf("File (%s %s) seems to be incompatible with current system (%s %s).\n",
+				new_vendor, new_board, cur_vendor, cur_board);
+			goto out;
+		}
+
+		/* Step 3: Check image version (so that we don't reflash the same image again and again) */
+		if (strcmp(cur_version, new_version) == 0) {
+			grub_printf("No need to update to the same version '%s'.\n", cur_version);
+			/* TODO: exit successfully. right? */
+			result = 0;
+			goto out;
+		}
+
+		/* Step 4: Merge current CMOS data with cmos.defaults */
+		/* Step 4a: Load new CMOS data */
+		void *cmos_defaults = cbfs_find_file("cmos.default", CBFS_COMPONENT_CMOS_DEFAULT);
+		void *cmos_layout = cbfs_find_file("cmos_layout.bin", CBFS_COMPONENT_CMOS_LAYOUT);
+		/* Step 4a1: Point use_mem to cmos.default. */
+		mem_accessor_base = cmos_defaults;
+		if (cmos_defaults && cmos_layout) {
+			/* Step 4b: Check if current CMOS data is valid. */
+			if (options_checksum_valid(use_nvram)) {
+				/* Step 4c: Iterate over current CMOS data */
+				struct cb_cmos_entries *cmos_entry = first_cmos_entry(get_system_option_table());
+				do {
+					/* Step 4c1: Attempt to update new CMOS data with current values. Ignore failures */
+					char *val = NULL;
+					get_option_as_string(use_nvram, get_system_option_table(), &val, cmos_entry->name);
+					if (val) {
+						set_option_from_string(use_mem, cmos_layout, val, cmos_entry->name);
+					}
+				} while (cmos_entry = next_cmos_entry(cmos_entry));
+			}
+
+			/* Step 5: Write merged CMOS image to CMOS */
+			/* TODO: do we need to skip 0x32 (RTC century)? */
+			int i;
+			for (i = 14; i < 256; i++)
+				nvram_write(((u8*)cmos_defaults)[i], i);
+
+			/* Step 6: Set cmos_defaults_loaded=no in CMOS data using new layout */
+			set_option_from_string(use_nvram, cmos_layout, "No", "cmos_defaults_loaded");
+
+			/* Step 6a: Set cmos_defaults_loaded=Yes in cmos.default in ROM image. */
+			set_option_from_string(use_mem, cmos_layout, "Yes", "cmos_defaults_loaded");
+		}
+	} else {
+		if (!force) {
+			grub_printf("This is a not a coreboot image. Aborting.\n");
+			goto out;
+		}
+	}
+
+	grub_printf("Writing image to flash, please wait.\n");
+	/* Step 7: Flash image */
+	if (write_flash(new_rom_data, new_rom_size) == 0) {
+		grub_printf("Flash was updated successfully.\n");
+		result = 0;
+		beep_success();
+	} else {
+		grub_printf("WARNING: Error while updating flash!!\n");
+		beep_fail();
+	}
+
+	/* success */
+	programmer_shutdown();
+
+out:
+	if (new_rom_data) free(new_rom_data);
+	new_rom_data = NULL;
+	if (argv) free(argv);
+	return result;
+}
+
diff --git a/main/grub/builtins.c b/main/grub/builtins.c
index f77a21a..8ebb829 100644
--- a/main/grub/builtins.c
+++ b/main/grub/builtins.c
@@ -549,7 +549,7 @@ static struct builtin builtin_find = {
 };
 #endif
 
-#ifdef CONFIG_FLASHROM_LOCKDOWN
+#ifdef CONFIG_FLASHROM_UNLOCK
 /* flashrom_unlock */
 /* Disable lockdown of flash memory on boot */
 static int flashrom_unlock_func(char *arg, int flags)
@@ -568,6 +568,18 @@ static struct builtin builtin_flashrom_unlock = {
 };
 #endif
 
+#ifdef CONFIG_FLASHUPDATE
+int flashupdate_func(char *arg, int flags);
+
+static struct builtin builtin_flashupdate = {
+	"flashupdate",
+	flashupdate_func,
+	BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+	"flashupdate DEVICE",
+	"Update flash ROM from a file loaded from DEVICE (selected by the user)."
+};
+#endif
+
 /* help */
 #define MAX_SHORT_DOC_LEN       39
 #define MAX_LONG_DOC_LEN        66
@@ -1924,9 +1936,12 @@ struct builtin *builtin_table[] = {
 #ifdef CONFIG_EXPERIMENTAL
 	&builtin_find,
 #endif
-#ifdef CONFIG_FLASHROM_LOCKDOWN
+#ifdef CONFIG_FLASHROM_UNLOCK
 	&builtin_flashrom_unlock,
 #endif
+#ifdef CONFIG_FLASHUPDATE
+	&builtin_flashupdate,
+#endif
 	&builtin_help,
 	&builtin_hiddenmenu,
 	&builtin_initrd,
diff --git a/x86/ldscript b/x86/ldscript
index b260c51..f701d37 100644
--- a/x86/ldscript
+++ b/x86/ldscript
@@ -26,9 +26,9 @@ OUTPUT_ARCH(i386)
 
 ENTRY(entry)
 
-/* 1024KB heap and 64KB stack */
-HEAP_SIZE = 1 * 1024 * 1024;
-STACK_SIZE = 64 * 1024;
+/* 96MB heap and 256KB stack */
+HEAP_SIZE = 96 * 1024 * 1024;
+STACK_SIZE = 256 * 1024;
 
 SECTIONS
 {



More information about the coreboot-gerrit mailing list