Hello Nico Huber,
I'd like you to do a code review. Please visit
https://review.coreboot.org/19190
to review the following change.
Change subject: Add a convenient libflashrom interface
......................................................................
Add a convenient libflashrom interface
This adds a minimal libflashrom interface based on the draft in the
wiki. While the glue code in libflashrom.c is build on top of the
existing code instead on overhauling it, the interface in libflashrom.h
is supposed to be stable. So we can keep the interface and adapt
internals later if favoured, without breaking clients.
A new make target, libinstall, is also added. It installs libflashrom.a
and libflashrom.h in lib/ and include/ dirs respectively.
This commit breaks build of the cli. It will be fixed with a follow-up
commit.
v2: Rebase and fixes by Anton Kochkov.
v3: o fl_image_*() rewritten with layout support (touch only included regions).
o Moved read/erase/write/verify operations to flashrom.c.
o Added layout pointer and flags to the flash context.
Change-Id: Ibd25aa58c165119a9f31ee9e9285bd793693d884
Signed-off-by: Nico Huber <nico.huber(a)secunet.com>
---
M Makefile
M flash.h
M flashrom.c
A libflashrom.c
A libflashrom.h
5 files changed, 695 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/90/19190/1
diff --git a/Makefile b/Makefile
index 8ddd6f3..b7f1991 100644
--- a/Makefile
+++ b/Makefile
@@ -519,7 +519,7 @@
###############################################################################
# Library code.
-LIB_OBJS = layout.o flashrom.o udelay.o programmer.o helpers.o
+LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o
###############################################################################
# Frontend related stuff.
@@ -1362,6 +1362,12 @@
$(INSTALL) -m 0755 $(PROGRAM)$(EXEC_SUFFIX) $(DESTDIR)$(PREFIX)/sbin
$(INSTALL) -m 0644 $(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8
+libinstall: libflashrom.a libflashrom.h
+ mkdir -p $(DESTDIR)$(PREFIX)/lib
+ $(INSTALL) -m 0644 libflashrom.a $(DESTDIR)$(PREFIX)/lib
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ $(INSTALL) -m 0644 libflashrom.h $(DESTDIR)$(PREFIX)/include
+
_export: $(PROGRAM).8
@rm -rf "$(EXPORTDIR)/flashrom-$(RELEASENAME)"
@mkdir -p "$(EXPORTDIR)/flashrom-$(RELEASENAME)"
diff --git a/flash.h b/flash.h
index be1134a..5544160 100644
--- a/flash.h
+++ b/flash.h
@@ -217,6 +217,12 @@
chipaddr virtual_registers;
struct registered_master *mst;
const struct fl_layout *layout;
+ struct {
+ bool force;
+ bool force_boardmismatch;
+ bool verify_after_write;
+ bool verify_whole_chip;
+ } flags;
};
/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
diff --git a/flashrom.c b/flashrom.c
index b6ba7e0..2f16e96 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -2460,3 +2460,296 @@
free(newcontents);
return ret;
}
+
+/** @private */
+static int prepare_flash_access(struct flashctx *const flash,
+ const bool read_it, const bool write_it,
+ const bool erase_it, const bool verify_it)
+{
+ if (chip_safety_check(flash, flash->flags.force, read_it, write_it, erase_it, verify_it)) {
+ msg_cerr("Aborting.\n");
+ return 1;
+ }
+
+ if (flash->layout == get_global_layout() && normalize_romentries(flash)) {
+ msg_cerr("Requested regions can not be handled. Aborting.\n");
+ return 1;
+ }
+
+ if (map_flash(flash) != 0)
+ return 1;
+
+ /* Given the existence of read locks, we want to unlock for read,
+ erase and write. */
+ if (flash->chip->unlock)
+ flash->chip->unlock(flash);
+
+ return 0;
+}
+
+/**
+ * @addtogroup fl-flash
+ * @{
+ */
+
+/**
+ * @brief Erase the specified ROM chip.
+ *
+ * If a layout is set in the given flash context, only included regions
+ * will be erased.
+ *
+ * @param flashctx The context of the flash chip to erase.
+ * @return 0 on success.
+ */
+int fl_flash_erase(struct flashctx *const flashctx)
+{
+ if (prepare_flash_access(flashctx, false, false, true, false))
+ return 1;
+
+ const int ret = erase_by_layout(flashctx);
+
+ unmap_flash(flashctx);
+
+ return ret;
+}
+
+/** @} */ /* end fl-flash */
+
+/**
+ * @defgroup fl-ops Operations
+ * @{
+ */
+
+/**
+ * @brief Read the current image from the specified ROM chip.
+ *
+ * If a layout is set in the specified flash context, only included regions
+ * will be read.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Target buffer to write image to.
+ * @param buffer_len Size of target buffer in bytes.
+ * @return 0 on success,
+ * 2 if buffer_len is to short for the flash chip's contents,
+ * or 1 on any other failure.
+ */
+int fl_image_read(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len)
+{
+ const size_t flash_size = flashctx->chip->total_size * 1024;
+
+ if (flash_size > buffer_len)
+ return 2;
+
+ if (prepare_flash_access(flashctx, true, false, false, false))
+ return 1;
+
+ msg_cinfo("Reading flash... ");
+
+ int ret = 1;
+ if (read_by_layout(flashctx, buffer)) {
+ msg_cerr("Read operation failed!\n");
+ msg_cinfo("FAILED.\n");
+ goto _unmap_ret;
+ }
+ msg_cinfo("done.\n");
+ ret = 0;
+
+_unmap_ret:
+ unmap_flash(flashctx);
+ return ret;
+}
+
+/** @private */
+static void combine_image_by_layout(const struct flashctx *const flashctx,
+ uint8_t *const newcontents, const uint8_t *const oldcontents)
+{
+ struct fl_layout_single fallback_layout;
+ const struct fl_layout *const layout = get_layout(flashctx, &fallback_layout);
+
+ size_t i;
+ for (i = 0; i < layout->num_entries; ++i) {
+ if (layout->entries[i].included)
+ continue;
+
+ const chipoff_t region_start = layout->entries[i].start;
+ const chipsize_t region_len = layout->entries[i].end - layout->entries[i].start + 1;
+
+ memcpy(newcontents + region_start, oldcontents + region_start, region_len);
+ }
+}
+
+/**
+ * @brief Write the specified image to the ROM chip.
+ *
+ * If a layout is set in the specified flash context, only erase blocks that
+ * lap included regions will be touched.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Source buffer to read image from.
+ * @param buffer_len Size of source buffer in bytes.
+ * @return 0 on success,
+ * 4 if buffer_len doesn't match the size of the flash chip,
+ * 3 if write was tried but nothing has changed,
+ * 2 if write failed and flash contents changed,
+ * or 1 on any other failure.
+ */
+int fl_image_write(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len)
+{
+ const size_t flash_size = flashctx->chip->total_size * 1024;
+ const bool verify_all = flashctx->flags.verify_whole_chip;
+ const bool verify = flashctx->flags.verify_after_write;
+
+ if (buffer_len != flash_size)
+ return 4;
+
+ int ret = 1;
+
+ uint8_t *const newcontents = buffer;
+ uint8_t *const curcontents = malloc(flash_size);
+ uint8_t *oldcontents = NULL;
+ if (verify_all)
+ oldcontents = malloc(flash_size);
+ if (!curcontents || (verify_all && !oldcontents)) {
+ msg_gerr("Out of memory!\n");
+ goto _free_ret;
+ }
+
+#if CONFIG_INTERNAL == 1
+ if (programmer == PROGRAMMER_INTERNAL && cb_check_image(newcontents, flash_size) < 0) {
+ if (flashctx->flags.force_boardmismatch) {
+ msg_pinfo("Proceeding anyway because user forced us to.\n");
+ } else {
+ msg_perr("Aborting. You can override this with "
+ "-p internal:boardmismatch=force.\n");
+ goto _free_ret;
+ }
+ }
+#endif
+
+ if (prepare_flash_access(flashctx, false, true, false, verify))
+ goto _free_ret;
+
+ /* Read the whole chip to be able to check whether regions need to be
+ * erased and to give better diagnostics in case write fails.
+ * The alternative is to read only the regions which are to be
+ * preserved, but in that case we might perform unneeded erase which
+ * takes time as well.
+ */
+ msg_cinfo("Reading old flash chip contents... ");
+ if (verify_all) {
+ if (flashctx->chip->read(flashctx, oldcontents, 0, flash_size)) {
+ msg_cinfo("FAILED.\n");
+ goto _unmap_ret;
+ }
+ memcpy(curcontents, oldcontents, flash_size);
+ } else {
+ if (read_by_layout(flashctx, curcontents)) {
+ msg_cinfo("FAILED.\n");
+ goto _unmap_ret;
+ }
+ }
+ msg_cinfo("done.\n");
+
+ if (write_by_layout(flashctx, curcontents, newcontents)) {
+ msg_cerr("Uh oh. Erase/write failed. ");
+ ret = 2;
+ if (verify_all) {
+ msg_cerr("Checking if anything has changed.\n");
+ msg_cinfo("Reading current flash chip contents... ");
+ if (!flashctx->chip->read(flashctx, curcontents, 0, flash_size)) {
+ msg_cinfo("done.\n");
+ if (!memcmp(oldcontents, curcontents, flash_size)) {
+ nonfatal_help_message();
+ goto _unmap_ret;
+ }
+ msg_cerr("Apparently at least some data has changed.\n");
+ } else
+ msg_cerr("Can't even read anymore!\n");
+ emergency_help_message();
+ goto _unmap_ret;
+ } else
+ msg_cerr("\n");
+ emergency_help_message();
+ goto _unmap_ret;
+ }
+
+ /* Verify only if we actually changed something. */
+ if (verify && !all_skipped) {
+ const struct fl_layout *const layout_bak = flashctx->layout;
+
+ msg_cinfo("Verifying flash... ");
+
+ /* Work around chips which need some time to calm down. */
+ programmer_delay(1000*1000);
+
+ if (verify_all) {
+ combine_image_by_layout(flashctx, newcontents, oldcontents);
+ flashctx->layout = NULL;
+ }
+ ret = verify_by_layout(flashctx, curcontents, newcontents);
+ flashctx->layout = layout_bak;
+ /* If we tried to write, and verification now fails, we
+ * might have an emergency situation.
+ */
+ if (ret)
+ emergency_help_message();
+ else
+ msg_cinfo("VERIFIED.\n");
+ } else {
+ /* We didn't change anything. */
+ ret = 0;
+ }
+
+_unmap_ret:
+ unmap_flash(flashctx);
+_free_ret:
+ free(oldcontents);
+ free(curcontents);
+ return ret;
+}
+
+/**
+ * @brief Verify the ROM chip's contents with the specified image.
+ *
+ * If a layout is set in the specified flash context, only included regions
+ * will be verified.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Source buffer to verify with.
+ * @param buffer_len Size of source buffer in bytes.
+ * @return 0 on success,
+ * 3 if the chip's contents don't match,
+ * 2 if buffer_len doesn't match the size of the flash chip,
+ * or 1 on any other failure.
+ */
+int fl_image_verify(struct flashctx *const flashctx, const void *const buffer, const size_t buffer_len)
+{
+ const size_t flash_size = flashctx->chip->total_size * 1024;
+
+ if (buffer_len != flash_size)
+ return 2;
+
+ const uint8_t *const newcontents = buffer;
+ uint8_t *const curcontents = malloc(flash_size);
+ if (!curcontents) {
+ msg_gerr("Out of memory!\n");
+ return 1;
+ }
+
+ int ret = 1;
+
+ if (prepare_flash_access(flashctx, false, false, false, true))
+ goto _free_ret;
+
+ msg_cinfo("Verifying flash... ");
+ ret = verify_by_layout(flashctx, curcontents, newcontents);
+ if (!ret)
+ msg_cinfo("VERIFIED.\n");
+
+ unmap_flash(flashctx);
+_free_ret:
+ free(curcontents);
+ return ret;
+}
+
+/** @} */ /* end fl-ops */
diff --git a/libflashrom.c b/libflashrom.c
new file mode 100644
index 0000000..eab9548
--- /dev/null
+++ b/libflashrom.c
@@ -0,0 +1,319 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2012, 2016 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber(a)secunet.com> for secunet)
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/**
+ * @mainpage
+ *
+ * Have a look at the Modules section for a function reference.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "flash.h"
+#include "programmer.h"
+#include "layout.h"
+#include "libflashrom.h"
+
+/**
+ * @defgroup fl-general General
+ * @{
+ */
+
+/** Pointer to log callback function. */
+static fl_log_callback_t *fl_log_callback = NULL;
+
+/**
+ * @brief Initialize libflashrom.
+ *
+ * @param perform_selfcheck If not zero, perform a self check.
+ * @return 0 on success
+ */
+int fl_init(const int perform_selfcheck)
+{
+ if (perform_selfcheck && selfcheck())
+ return 1;
+ myusec_calibrate_delay();
+ return 0;
+}
+
+/**
+ * @brief Shut down libflashrom.
+ * @return 0 on success
+ */
+int fl_shutdown(void)
+{
+ return 0; /* TODO: nothing to do? */
+}
+
+/* TODO: fl_set_loglevel()? do we need it?
+ For now, let the user decide in his callback. */
+
+/**
+ * @brief Set the log callback function.
+ *
+ * Set a callback function which will be invoked whenever libflashrom wants
+ * to output messages. This allows frontends to do whatever they see fit with
+ * such messages, e.g. write them to syslog, or to file, or print them in a
+ * GUI window, etc.
+ *
+ * @param log_callback Pointer to the new log callback function.
+ */
+void fl_set_log_callback(fl_log_callback_t *const log_callback)
+{
+ fl_log_callback = log_callback;
+}
+/** @private */
+int print(const enum msglevel level, const char *const fmt, ...)
+{
+ if (fl_log_callback) {
+ int ret;
+ va_list args;
+ va_start(args, fmt);
+ ret = fl_log_callback(level, fmt, args);
+ va_end(args);
+ return ret;
+ }
+ return 0;
+}
+
+/** @} */ /* end fl-general */
+
+
+
+/**
+ * @defgroup fl-query Querying
+ * @{
+ */
+
+/* TBD */
+
+/** @} */ /* end fl-query */
+
+
+
+/**
+ * @defgroup fl-prog Programmers
+ * @{
+ */
+
+/**
+ * @brief Initialize the specified programmer.
+ *
+ * @param prog_name Name of the programmer to initialize.
+ * @param prog_param Pointer to programmer specific parameters.
+ * @return 0 on success
+ */
+int fl_programmer_init(const char *const prog_name, const char *const prog_param)
+{
+ unsigned prog;
+
+ for (prog = 0; prog < PROGRAMMER_INVALID; prog++) {
+ if (strcmp(prog_name, programmer_table[prog].name) == 0)
+ break;
+ }
+ if (prog >= PROGRAMMER_INVALID) {
+ msg_ginfo("Error: Unknown programmer \"%s\". Valid choices are:\n", prog_name);
+ list_programmers_linebreak(0, 80, 0);
+ return 1;
+ }
+ return programmer_init(prog, prog_param);
+}
+
+/**
+ * @brief Shut down the initialized programmer.
+ *
+ * @return 0 on success
+ */
+int fl_programmer_shutdown(void)
+{
+ return programmer_shutdown();
+}
+
+/* TODO: fl_programmer_capabilities()? */
+
+/** @} */ /* end fl-prog */
+
+
+
+/**
+ * @defgroup fl-flash Flash chips
+ * @{
+ */
+
+/**
+ * @brief Probe for a flash chip.
+ *
+ * Probes for a flash chip and returns a flash context, that can be used
+ * later with flash chip and @ref fl-ops "image operations", if exactly one
+ * matching chip is found.
+ *
+ * @param[out] flashctx Points to a pointer of type fl_flashctx_t that will
+ * be set if exactly one chip is found. *flashctx has
+ * to be freed by the caller with @ref fl_flash_release.
+ * @param[in] chip_name Name of a chip to probe for, or NULL to probe for
+ * all known chips.
+ * @return 0 on success,
+ * 3 if multiple chips were found,
+ * 2 if no chip was found,
+ * or 1 on any other error.
+ */
+int fl_flash_probe(struct flashctx **const flashctx, const char *const chip_name)
+{
+ int i, ret = 2;
+ struct flashctx second_flashctx = { 0, };
+
+ chip_to_probe = chip_name; /* chip_to_probe is global in flashrom.c */
+
+ *flashctx = malloc(sizeof(**flashctx));
+ if (!*flashctx)
+ return 1;
+ memset(*flashctx, 0, sizeof(**flashctx));
+
+ for (i = 0; i < registered_master_count; ++i) {
+ int flash_idx = -1;
+ if (!ret || (flash_idx = probe_flash(®istered_masters[i], 0, *flashctx, 0)) != -1) {
+ ret = 0;
+ /* We found one chip, now check that there is no second match. */
+ if (probe_flash(®istered_masters[i], flash_idx + 1, &second_flashctx, 0) != -1) {
+ ret = 3;
+ break;
+ }
+ }
+ }
+ if (ret) {
+ free(*flashctx);
+ *flashctx = NULL;
+ }
+ return ret;
+}
+
+/**
+ * @brief Returns the size of the specified flash chip in bytes.
+ *
+ * @param flashctx The queried flash context.
+ * @return Size of flash chip in bytes.
+ */
+size_t fl_flash_getsize(const struct flashctx *const flashctx)
+{
+ return flashctx->chip->total_size << 10;
+}
+
+/**
+ * @brief Free a flash context.
+ *
+ * @param flashctx Flash context to free.
+ */
+void fl_flash_release(struct flashctx *const flashctx)
+{
+ free(flashctx);
+}
+
+/**
+ * @brief Set a flag in the given flash context.
+ *
+ * @param flashctx Flash context to alter.
+ * @param flag Flag that is to be set / cleared.
+ * @param value Value to set.
+ */
+void fl_flag_set(fl_flashctx_t *const flashctx, const enum fl_flag flag, const bool value)
+{
+ switch (flag) {
+ case FL_FLAG_FORCE: flashctx->flags.force = value; break;
+ case FL_FLAG_FORCE_BOARDMISMATCH: flashctx->flags.force_boardmismatch = value; break;
+ case FL_FLAG_VERIFY_AFTER_WRITE: flashctx->flags.verify_after_write = value; break;
+ case FL_FLAG_VERIFY_WHOLE_CHIP: flashctx->flags.verify_whole_chip = value; break;
+ }
+}
+
+/**
+ * @brief Return the current value of a flag in the given flash context.
+ *
+ * @param flashctx Flash context to read from.
+ * @param flag Flag to be read.
+ * @return Current value of the flag.
+ */
+bool fl_flag_get(const fl_flashctx_t *const flashctx, const enum fl_flag flag)
+{
+ switch (flag) {
+ case FL_FLAG_FORCE: return flashctx->flags.force;
+ case FL_FLAG_FORCE_BOARDMISMATCH: return flashctx->flags.force_boardmismatch;
+ case FL_FLAG_VERIFY_AFTER_WRITE: return flashctx->flags.verify_after_write;
+ case FL_FLAG_VERIFY_WHOLE_CHIP: return flashctx->flags.verify_whole_chip;
+ default: return false;
+ }
+}
+
+/** @} */ /* end fl-flash */
+
+
+
+/**
+ * @defgroup fl-layout Layout handling
+ * @{
+ */
+
+/**
+ * @brief Mark given region as included.
+ *
+ * @param layout The layout to alter.
+ * @param name The name of the region to include.
+ *
+ * @return 0 on success,
+ * 1 if the given name can't be found.
+ */
+int fl_layout_include_region(fl_layout_t *const layout, const char *name)
+{
+ size_t i;
+ for (i = 0; i < layout->num_entries; ++i) {
+ if (!strcmp(layout->entries[i].name, name)) {
+ layout->entries[i].included = true;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**
+ * @brief Free a layout.
+ *
+ * @param layout Layout to free.
+ */
+void fl_layout_release(struct fl_layout *const layout)
+{
+ free(layout);
+}
+
+/**
+ * @brief Set the active layout for a flash context.
+ *
+ * Note: This just sets a pointer. The caller must not release the layout
+ * as long as he uses it through the given flash context.
+ *
+ * @param flashctx Flash context whose layout will be set.
+ * @param layout Layout to bet set.
+ */
+void fl_layout_set(struct flashctx *const flashctx, const struct fl_layout *const layout)
+{
+ flashctx->layout = layout;
+}
+
+/** @} */ /* end fl-layout */
diff --git a/libflashrom.h b/libflashrom.h
new file mode 100644
index 0000000..af56bc8
--- /dev/null
+++ b/libflashrom.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2012 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber(a)secunet.com> for secunet)
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIBFLASHROM_H__
+#define __LIBFLASHROM_H__ 1
+
+#include <stdarg.h>
+
+int fl_init(int perform_selfcheck);
+int fl_shutdown(void);
+/** @ingroup fl-general */
+enum fl_log_level { /* This has to match enum msglevel. */
+ FL_MSG_ERROR = 0,
+ FL_MSG_INFO = 1,
+ FL_MSG_DEBUG = 2,
+ FL_MSG_DEBUG2 = 3,
+ FL_MSG_SPEW = 4,
+};
+/** @ingroup fl-general */
+typedef int(fl_log_callback_t)(enum fl_log_level, const char *format, va_list);
+void fl_set_log_callback(fl_log_callback_t *);
+
+int fl_programmer_init(const char *prog_name, const char *prog_params);
+int fl_programmer_shutdown(void);
+
+struct flashctx;
+typedef struct flashctx fl_flashctx_t;
+int fl_flash_probe(fl_flashctx_t **, const char *chip_name);
+size_t fl_flash_getsize(const fl_flashctx_t *);
+int fl_flash_erase(fl_flashctx_t *);
+void fl_flash_release(fl_flashctx_t *);
+
+enum fl_flag {
+ FL_FLAG_FORCE,
+ FL_FLAG_FORCE_BOARDMISMATCH,
+ FL_FLAG_VERIFY_AFTER_WRITE,
+ FL_FLAG_VERIFY_WHOLE_CHIP,
+};
+void fl_flag_set(fl_flashctx_t *, enum fl_flag, bool value);
+bool fl_flag_get(const fl_flashctx_t *, enum fl_flag);
+
+int fl_image_read(fl_flashctx_t *, void *buffer, size_t buffer_len);
+int fl_image_write(fl_flashctx_t *, const void *buffer, size_t buffer_len);
+int fl_image_verify(fl_flashctx_t *, const void *buffer, size_t buffer_len);
+
+struct fl_layout;
+typedef struct fl_layout fl_layout_t;
+int fl_layout_include_region(fl_layout_t *, const char *name);
+void fl_layout_release(fl_layout_t *);
+void fl_layout_set(fl_flashctx_t *, const fl_layout_t *);
+
+#endif /* !__LIBFLASHROM_H__ */
--
To view, visit https://review.coreboot.org/19190
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibd25aa58c165119a9f31ee9e9285bd793693d884
Gerrit-PatchSet: 1
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
Hello Nico Huber,
I'd like you to do a code review. Please visit
https://review.coreboot.org/19189
to review the following change.
Change subject: Add functions to read/erase/write/verify by layout
......................................................................
Add functions to read/erase/write/verify by layout
Inspired by Lynxis' related work, this implements a foundation for
layout based flash access.
All operations iterate over the given layout regions. Erase and write
then walk, per region, over all erase blocks in an inner loop (which
might not be what we want, see note on optimization below). Special care
has been taken that flash content is merged properly, in case an erase
block is only partially covered by a layout region or even affects mul-
tiple regions.
A note on performance: In the case an erase block affects multiple
regions, it will probably be read, erased and written for each region.
Another approach would be to walk all erase blocks once and check for
each erase block which regions it touches (i.e. for each erase block,
merge data pontentially from the flash and all layout regions, then
flash the combined data). That might result in cleaner code. I haven't
tried it yet, though.
Change-Id: I060d9c42d71c83c3f95a6189cd22dad8b1504784
Signed-off-by: Nico Huber <nico.huber(a)secunet.com>
---
M flash.h
M flashrom.c
2 files changed, 327 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/89/19189/1
diff --git a/flash.h b/flash.h
index bf381cf..be1134a 100644
--- a/flash.h
+++ b/flash.h
@@ -216,6 +216,7 @@
uintptr_t physical_registers;
chipaddr virtual_registers;
struct registered_master *mst;
+ const struct fl_layout *layout;
};
/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
diff --git a/flashrom.c b/flashrom.c
index 1a43303..b6ba7e0 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -5,6 +5,8 @@
* Copyright (C) 2004 Tyan Corp <yhlu(a)tyan.com>
* Copyright (C) 2005-2008 coresystems GmbH
* Copyright (C) 2008,2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2016 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber(a)secunet.com> for secunet)
*
* 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
@@ -1640,6 +1642,330 @@
return ret;
}
+/** @private */
+static const struct fl_layout *get_layout(const struct flashctx *const flashctx,
+ struct fl_layout_single *const fallback)
+{
+ if (flashctx->layout && flashctx->layout->num_entries)
+ return flashctx->layout;
+
+ fallback->base.entries = &fallback->entry;
+ fallback->base.num_entries = 1;
+ fallback->entry.start = 0;
+ fallback->entry.end = flashctx->chip->total_size * 1024 - 1;
+ fallback->entry.included = true;
+ strcpy(fallback->entry.name, "complete flash");
+ return &fallback->base;
+}
+
+/**
+ * @brief Reads the included layout regions into a buffer.
+ *
+ * If there is no layout set in the given flash context, the whole chip will
+ * be read.
+ *
+ * @param flashctx Flash context to be used.
+ * @param buffer Buffer of full chip size to read into.
+ * @return 0 on success,
+ * 1 if any read fails.
+ */
+static int read_by_layout(struct flashctx *const flashctx, void *const buffer)
+{
+ struct fl_layout_single fallback_layout;
+ const struct fl_layout *const layout = get_layout(flashctx, &fallback_layout);
+
+ size_t i;
+ for (i = 0; i < layout->num_entries; ++i) {
+ if (!layout->entries[i].included)
+ continue;
+
+ const chipoff_t region_start = layout->entries[i].start;
+ const chipsize_t region_len = layout->entries[i].end - layout->entries[i].start + 1;
+
+ if (flashctx->chip->read(flashctx, buffer + region_start, region_start, region_len))
+ return 1;
+ }
+ return 0;
+}
+
+typedef int (*erasefn_t)(struct flashctx *, unsigned int addr, unsigned int len);
+struct walk_info {
+ uint8_t *curcontents;
+ const uint8_t *newcontents;
+ unsigned int region_start;
+ unsigned int region_end;
+ unsigned int erase_start;
+ unsigned int erase_end;
+};
+typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t);
+
+/** @private */
+static int walk_eraseblocks(struct flashctx *const flashctx,
+ struct walk_info *const info,
+ const int erasefunction, per_blockfn_t per_blockfn)
+{
+ int ret;
+ int i, j;
+ bool first = true;
+ struct block_eraser *const eraser = &flashctx->chip->block_erasers[erasefunction];
+
+ info->erase_start = 0;
+ for (i = 0; i < NUM_ERASEREGIONS; i++) {
+ /* count==0 for all automatically initialized array
+ * members so the loop below won't be executed for them.
+ */
+ for (j = 0; j < eraser->eraseblocks[i].count; ++j, info->erase_start = info->erase_end + 1) {
+ info->erase_end = info->erase_start + eraser->eraseblocks[i].size - 1;
+
+ /* Skip any eraseblock that is completely outside the current region. */
+ if (info->erase_end < info->region_start || info->region_end < info->erase_start)
+ continue;
+
+ /* Print this for every block except the first one. */
+ if (first)
+ first = false;
+ else
+ msg_cdbg(", ");
+ msg_cdbg("0x%06x-0x%06x:", info->erase_start, info->erase_end);
+
+ ret = per_blockfn(flashctx, info, eraser->block_erase);
+ if (ret)
+ return ret;
+ }
+ }
+ msg_cdbg("\n");
+ return 0;
+}
+
+/** @private */
+static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *const info,
+ per_blockfn_t per_blockfn)
+{
+ struct fl_layout_single fallback_layout;
+ const struct fl_layout *const layout = get_layout(flashctx, &fallback_layout);
+
+ all_skipped = true;
+ msg_cinfo("Erasing and writing flash chip... ");
+
+ size_t i;
+ for (i = 0; i < layout->num_entries; ++i) {
+ if (!layout->entries[i].included)
+ continue;
+
+ info->region_start = layout->entries[i].start;
+ info->region_end = layout->entries[i].end;
+
+ size_t j;
+ int ret = 1;
+ for (j = 0; j < NUM_ERASEFUNCTIONS; ++j) {
+ if (j != 0)
+ msg_cinfo("Looking for another erase function.\n");
+ msg_cdbg("Trying erase function %zi... ", j);
+ if (check_block_eraser(flashctx, j, 1))
+ continue;
+
+ ret = walk_eraseblocks(flashctx, info, j, per_blockfn);
+ if (ret != 1)
+ break;
+
+ if (info->curcontents) {
+ msg_cinfo("Reading current flash chip contents... ");
+ if (read_by_layout(flashctx, info->curcontents)) {
+ /* Now we are truly screwed. Read failed as well. */
+ msg_cerr("Can't read anymore! Aborting.\n");
+ /* We have no idea about the flash chip contents, so
+ * retrying with another erase function is pointless.
+ */
+ ret = 2;
+ break;
+ }
+ msg_cinfo("done. ");
+ }
+ }
+ if (ret == 1)
+ msg_cinfo("No usable erase functions left.\n");
+ if (ret) {
+ msg_cerr("FAILED!\n");
+ return 1;
+ }
+ }
+ if (all_skipped)
+ msg_cinfo("\nWarning: Chip content is identical to the requested image.\n");
+ msg_cinfo("Erase/write done.\n");
+ return 0;
+}
+
+/** @private */
+static int erase_block(struct flashctx *const flashctx, const struct walk_info *const info, erasefn_t erasefn)
+{
+ const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
+
+ all_skipped = false;
+
+ msg_cdbg("E");
+ if (erasefn(flashctx, info->erase_start, erase_len))
+ return 1;
+ if (check_erased_range(flashctx, info->erase_start, erase_len)) {
+ msg_cerr("ERASE FAILED!\n");
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Erases the included layout regions.
+ *
+ * If there is no layout set in the given flash context, the whole chip will
+ * be erased.
+ *
+ * @param flashctx Flash context to be used.
+ * @param buffer Buffer of full chip size to read into.
+ * @return 0 on success,
+ * 1 if all available erase functions failed.
+ */
+static int erase_by_layout(struct flashctx *const flashctx)
+{
+ struct walk_info info = { 0 };
+ return walk_by_layout(flashctx, &info, erase_block);
+}
+
+/** @private */
+static int read_erase_write_block(struct flashctx *const flashctx,
+ const struct walk_info *const info, erasefn_t erasefn)
+{
+ const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
+ const bool region_unaligned = info->region_start > info->erase_start ||
+ info->erase_end > info->region_end;
+ const uint8_t *newcontents = NULL;
+ int ret = 2;
+ /*
+ * Merge current flash contents into new buffer if the region is not erase-block
+ * aligned.
+ * Note: We can not use newcontents here as this erase block might overlap
+ * other regions as well. So we would invalidate data to be written there.
+ */
+ if (region_unaligned) {
+ msg_cdbg("R");
+ uint8_t *const newc = malloc(erase_len);
+ if (!newc) {
+ msg_cerr("Out of memory!\n");
+ return 1;
+ }
+ memcpy(newc, info->newcontents + info->erase_start, erase_len);
+ if (info->region_start > info->erase_start &&
+ flashctx->chip->read(flashctx, newc,
+ info->erase_start, info->region_start - info->erase_start)) {
+ msg_cerr("Can't read! Aborting.\n");
+ goto _free_ret;
+ }
+ if (info->erase_end > info->region_end &&
+ flashctx->chip->read(flashctx, newc - info->erase_start + info->region_end + 1,
+ info->region_end + 1, info->erase_end - info->region_end)) {
+ msg_cerr("Can't read! Aborting.\n");
+ goto _free_ret;
+ }
+ newcontents = newc;
+ } else {
+ newcontents = info->newcontents + info->erase_start;
+ }
+
+ ret = 1;
+ bool skipped = true;
+ uint8_t *const curcontents = info->curcontents + info->erase_start;
+ if (need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran)) {
+ if (erase_block(flashctx, info, erasefn))
+ goto _free_ret;
+ /* Erase was successful. Adjust curcontents. */
+ memset(curcontents, 0xff, erase_len);
+ skipped = false;
+ }
+
+ unsigned int starthere = 0, lenhere = 0, writecount = 0;
+ /* get_next_write() sets starthere to a new value after the call. */
+ while ((lenhere = get_next_write(curcontents + starthere, newcontents + starthere,
+ erase_len - starthere, &starthere, flashctx->chip->gran))) {
+ if (!writecount++)
+ msg_cdbg("W");
+ /* Needs the partial write function signature. */
+ if (flashctx->chip->write(flashctx, newcontents + starthere,
+ info->erase_start + starthere, lenhere))
+ goto _free_ret;
+ starthere += lenhere;
+ skipped = false;
+ }
+ if (skipped)
+ msg_cdbg("S");
+ else
+ all_skipped = false;
+
+ /* Update curcontents, other regions with overlapping erase blocks
+ might rely on this. */
+ memcpy(curcontents, newcontents, erase_len);
+ ret = 0;
+
+_free_ret:
+ if (region_unaligned)
+ free((void *)newcontents);
+ return ret;
+}
+
+/**
+ * @brief Writes the included layout regions from a given image.
+ *
+ * If there is no layout set in the given flash context, the whole image
+ * will be written.
+ *
+ * @param flashctx Flash context to be used.
+ * @param curcontents A buffer of full chip size with current chip contents of included regions.
+ * @param newcontents The new image to be written.
+ * @return 0 on success,
+ * 1 if anything has gone wrong.
+ */
+static int write_by_layout(struct flashctx *const flashctx,
+ void *const curcontents, const void *const newcontents)
+{
+ struct walk_info info;
+ info.curcontents = curcontents;
+ info.newcontents = newcontents;
+ return walk_by_layout(flashctx, &info, read_erase_write_block);
+}
+
+/**
+ * @brief Compares the included layout regions with content from a buffer.
+ *
+ * If there is no layout set in the given flash context, the whole chip's
+ * contents will be compared.
+ *
+ * @param flashctx Flash context to be used.
+ * @param curcontents A buffer of full chip size to read current chip contents into.
+ * @param newcontents The new image to compare to.
+ * @return 0 on success,
+ * 1 if reading failed,
+ * 3 if the contents don't match.
+ */
+static int verify_by_layout(struct flashctx *const flashctx,
+ void *const curcontents, const void *const newcontents)
+{
+ struct fl_layout_single fallback_layout;
+ const struct fl_layout *const layout = get_layout(flashctx, &fallback_layout);
+
+ size_t i;
+ for (i = 0; i < layout->num_entries; ++i) {
+ if (!layout->entries[i].included)
+ continue;
+
+ const chipoff_t region_start = layout->entries[i].start;
+ const chipsize_t region_len = layout->entries[i].end - layout->entries[i].start + 1;
+
+ if (flashctx->chip->read(flashctx, curcontents + region_start, region_start, region_len))
+ return 1;
+ if (compare_range(newcontents + region_start, curcontents + region_start,
+ region_start, region_len))
+ return 3;
+ }
+ return 0;
+}
+
static void nonfatal_help_message(void)
{
msg_gerr("Good, writing to the flash chip apparently didn't do anything.\n");
--
To view, visit https://review.coreboot.org/19189
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I060d9c42d71c83c3f95a6189cd22dad8b1504784
Gerrit-PatchSet: 1
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
Hello Nico Huber,
I'd like you to do a code review. Please visit
https://review.coreboot.org/19188
to review the following change.
Change subject: Give layouts their own type
......................................................................
Give layouts their own type
Introduce `struct fl_layout` and refactor layout.c a little, so we can
reuse the layout from there and have other sources of layouts beside it.
I didn't want to clutter up flash.h any more. So things went into a new
layout.h.
Change-Id: Ic728fc9f64958f62a2e2f321f4ec440e8658c808
Signed-off-by: Nico Huber <nico.huber(a)secunet.com>
---
M flash.h
M layout.c
A layout.h
3 files changed, 99 insertions(+), 50 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/88/19188/1
diff --git a/flash.h b/flash.h
index da049d1..bf381cf 100644
--- a/flash.h
+++ b/flash.h
@@ -37,6 +37,8 @@
#undef max
#endif
+#include "layout.h"
+
#define ERROR_PTR ((void*)-1)
/* Error codes */
@@ -46,14 +48,6 @@
/* TODO: check using code for correct usage of types */
typedef uintptr_t chipaddr;
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))
-
-/* Types and macros regarding the maximum flash space size supported by generic code. */
-typedef uint32_t chipoff_t; /* Able to store any addressable offset within a supported flash memory. */
-typedef uint32_t chipsize_t; /* Able to store the number of bytes of any supported flash memory. */
-#define FL_MAX_CHIPOFF_BITS (24)
-#define FL_MAX_CHIPOFF ((chipoff_t)(1ULL<<FL_MAX_CHIPOFF_BITS)-1)
-#define PRIxCHIPOFF "06"PRIx32
-#define PRIuCHIPSIZE PRIu32
int register_shutdown(int (*function) (void *data), void *data);
int shutdown_free(void *data);
diff --git a/layout.c b/layout.c
index f71eeaa..9eadb22 100644
--- a/layout.c
+++ b/layout.c
@@ -25,24 +25,20 @@
#include <limits.h>
#include "flash.h"
#include "programmer.h"
+#include "layout.h"
-#define MAX_ROMLAYOUT 32
-
-typedef struct {
- chipoff_t start;
- chipoff_t end;
- unsigned int included;
- char name[256];
-} romentry_t;
-
-/* rom_entries store the entries specified in a layout file and associated run-time data */
-static romentry_t rom_entries[MAX_ROMLAYOUT];
-static int num_rom_entries = 0; /* the number of successfully parsed rom_entries */
+struct fl_romentry entries[MAX_ROMLAYOUT];
+static struct fl_layout layout = { entries, 0 };
/* include_args holds the arguments specified at the command line with -i. They must be processed at some point
- * so that desired regions are marked as "included" in the rom_entries list. */
+ * so that desired regions are marked as "included" in the layout. */
static char *include_args[MAX_ROMLAYOUT];
static int num_include_args = 0; /* the number of valid include_args. */
+
+const struct fl_layout *get_global_layout(void)
+{
+ return &layout;
+}
#ifndef __LIBPAYLOAD__
int read_romlayout(const char *name)
@@ -62,13 +58,13 @@
while (!feof(romlayout)) {
char *tstr1, *tstr2;
- if (num_rom_entries >= MAX_ROMLAYOUT) {
+ if (layout.num_entries >= MAX_ROMLAYOUT) {
msg_gerr("Maximum number of ROM images (%i) in layout "
"file reached.\n", MAX_ROMLAYOUT);
(void)fclose(romlayout);
return 1;
}
- if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, rom_entries[num_rom_entries].name))
+ if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, layout.entries[layout.num_entries].name))
continue;
#if 0
// fscanf does not like arbitrary comments like that :( later
@@ -83,16 +79,16 @@
(void)fclose(romlayout);
return 1;
}
- rom_entries[num_rom_entries].start = strtol(tstr1, (char **)NULL, 16);
- rom_entries[num_rom_entries].end = strtol(tstr2, (char **)NULL, 16);
- rom_entries[num_rom_entries].included = 0;
- num_rom_entries++;
+ layout.entries[layout.num_entries].start = strtol(tstr1, (char **)NULL, 16);
+ layout.entries[layout.num_entries].end = strtol(tstr2, (char **)NULL, 16);
+ layout.entries[layout.num_entries].included = 0;
+ layout.num_entries++;
}
- for (i = 0; i < num_rom_entries; i++) {
+ for (i = 0; i < layout.num_entries; i++) {
msg_gdbg("romlayout %08x - %08x named %s\n",
- rom_entries[i].start,
- rom_entries[i].end, rom_entries[i].name);
+ layout.entries[i].start,
+ layout.entries[i].end, layout.entries[i].name);
}
(void)fclose(romlayout);
@@ -140,13 +136,13 @@
{
int i;
- if (num_rom_entries == 0)
+ if (layout.num_entries == 0)
return -1;
msg_gspew("Looking for region \"%s\"... ", name);
- for (i = 0; i < num_rom_entries; i++) {
- if (!strcmp(rom_entries[i].name, name)) {
- rom_entries[i].included = 1;
+ for (i = 0; i < layout.num_entries; i++) {
+ if (!strcmp(layout.entries[i].name, name)) {
+ layout.entries[i].included = 1;
msg_gspew("found.\n");
return i;
}
@@ -167,7 +163,7 @@
return 0;
/* User has specified an area, but no layout file is loaded. */
- if (num_rom_entries == 0) {
+ if (layout.num_entries == 0) {
msg_gerr("Region requested (with -i \"%s\"), "
"but no layout data is available.\n",
include_args[0]);
@@ -200,22 +196,22 @@
}
num_include_args = 0;
- for (i = 0; i < num_rom_entries; i++) {
- rom_entries[i].included = 0;
+ for (i = 0; i < layout.num_entries; i++) {
+ layout.entries[i].included = 0;
}
- num_rom_entries = 0;
+ layout.num_entries = 0;
}
-romentry_t *get_next_included_romentry(unsigned int start)
+struct fl_romentry *get_next_included_romentry(unsigned int start)
{
int i;
unsigned int best_start = UINT_MAX;
- romentry_t *best_entry = NULL;
- romentry_t *cur;
+ struct fl_romentry *best_entry = NULL;
+ struct fl_romentry *cur;
/* First come, first serve for overlapping regions. */
- for (i = 0; i < num_rom_entries; i++) {
- cur = &rom_entries[i];
+ for (i = 0; i < layout.num_entries; i++) {
+ cur = &layout.entries[i];
if (!cur->included)
continue;
/* Already past the current entry? */
@@ -240,16 +236,16 @@
int ret = 0;
int i;
- for (i = 0; i < num_rom_entries; i++) {
- if (rom_entries[i].start >= total_size || rom_entries[i].end >= total_size) {
+ for (i = 0; i < layout.num_entries; i++) {
+ if (layout.entries[i].start >= total_size || layout.entries[i].end >= total_size) {
msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's "
- "address space.\n", rom_entries[i].name);
- if (rom_entries[i].included)
+ "address space.\n", layout.entries[i].name);
+ if (layout.entries[i].included)
ret = 1;
}
- if (rom_entries[i].start > rom_entries[i].end) {
+ if (layout.entries[i].start > layout.entries[i].end) {
msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n",
- rom_entries[i].name);
+ layout.entries[i].name);
ret = 1;
}
}
@@ -281,7 +277,7 @@
int build_new_image(struct flashctx *flash, bool oldcontents_valid, uint8_t *oldcontents, uint8_t *newcontents)
{
unsigned int start = 0;
- romentry_t *entry;
+ struct fl_romentry *entry;
unsigned int size = flash->chip->total_size * 1024;
/* If no regions were specified for inclusion, assume
diff --git a/layout.h b/layout.h
new file mode 100644
index 0000000..3aebe8a
--- /dev/null
+++ b/layout.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * (Written by Stefan Reinauer <stepan(a)coresystems.de> for coresystems GmbH)
+ * Copyright (C) 2011-2013 Stefan Tauner
+ * Copyright (C) 2016 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber(a)secunet.com> for secunet)
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LAYOUT_H__
+#define __LAYOUT_H__ 1
+
+/* Types and macros regarding the maximum flash space size supported by generic code. */
+typedef uint32_t chipoff_t; /* Able to store any addressable offset within a supported flash memory. */
+typedef uint32_t chipsize_t; /* Able to store the number of bytes of any supported flash memory. */
+#define FL_MAX_CHIPOFF_BITS (24)
+#define FL_MAX_CHIPOFF ((chipoff_t)(1ULL<<FL_MAX_CHIPOFF_BITS)-1)
+#define PRIxCHIPOFF "06"PRIx32
+#define PRIuCHIPSIZE PRIu32
+
+#define MAX_ROMLAYOUT 32
+
+struct fl_romentry {
+ chipoff_t start;
+ chipoff_t end;
+ bool included;
+ char name[256];
+};
+
+struct fl_layout {
+ /* entries store the entries specified in a layout file and associated run-time data */
+ struct fl_romentry *entries;
+ /* the number of successfully parsed entries */
+ int num_entries;
+};
+
+struct fl_layout_single {
+ struct fl_layout base;
+ struct fl_romentry entry;
+};
+
+const struct fl_layout *get_global_layout(void);
+
+#endif /* !__LAYOUT_H__ */
--
To view, visit https://review.coreboot.org/19188
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic728fc9f64958f62a2e2f321f4ec440e8658c808
Gerrit-PatchSet: 1
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
David Hendricks has uploaded a new patch set (#2). ( https://review.coreboot.org/19185 )
Change subject: This is a combination of 2 commits. The first commit's message is:
......................................................................
This is a combination of 2 commits.
The first commit's message is:
Convert flashrom to git
- Drop support for Subversion in the getrevision script and Makefile.
- Add .gitignore and .gitattributes file (the latter to limit exports).
- Restore modification dates of the exported files from the SCM.
- Stop exporting SCM log dumps to CHANGELOG. This makes no sense.
- Remove djgpp-dos target (it is not different to other x-compilations).
- Do not export the pre-"compiled" manpage. It can be generated like
anything else from the code dump when we export the respective variable.
The latter is added with this change.
- Add some initial client-side git hooks
* When committing check for obvious stuff you never want anyway:
- white space errors
- duplicate sign-offs
* When pushing to the upstream repository check mandatory rules:
- existing signoffs and acks in all new commits
- no deletions or creation of branches
- do not rewrite history of the precious branches, even if forced
- Change version string of flashrom as follows.
Previously, we included the last stable version according to a hard-
coded string in the Makefile and appended the subversion revision number.
With this patch the version string includes the last reachable git tag,
number of commits since said tag in the upstream branches (if any),
the name of said upstream branch, number of commits since that branch
(if any), and the shortened git hash.
In case there are uncommitted changes a "-dirty" indicator is also added.
The case of unknown versions is explicitly handled in getrevision instead
of simply appending "-unknown" to a hardcoded release number.
The version information is either taken from an existing git remote
pointing to an upstream repository (or a known mirror), or if that
is not available - with the user's consent - a shadow copy is fetched
from the upstream repo that is updated on every build (usually takes
less than a second).
In the following some examples of the version string changes are shown.
Basically we print the distance to the last known upstream tag, which
comprises any upstream commits since that tag as well as local commits on
top of that. Additionally we handle upstream's stable and staging branches
specially.
Old output:
flashrom v0.9.7-r1716 on Linux 3.8.0-6-generic (x86_64)
New output variants:
Build of the 0.9.99 release without any changes:
flashrom v0.9.99-e4f6643 on Linux 3.13.0-76-generic (x86_64)
5 commits since last tag in upstream's stable branch:
flashrom v0.9.99-5-stable-e4f6643-dirty on Linux 3.13.0-76-generic (x86_64)
3 commits since last tag in upstream's staging branch and
4 local commits on top of that:
flashrom v0.9.99-3-staging-4-e4f6643 on Linux 3.13.0-76-generic (x86_64)
3 commits since last tag in upstream's staging branch and
4 local commits on top of that, and some local uncommitted changes too:
flashrom v0.9.99-3-staging-4-e4f6643-dirty on Linux 3.13.0-76-generic (x86_64)
3 commits since the last tag in an unrelated upstream branch
(e.g., a stable release *branch* such as 0.9.99.x) or local branch:
flashrom v0.9.99-3-e4f6643 on Linux 3.13.0-76-generic (x86_64)
No tags reachable from current commit (generic git fallback):
flashrom d95935a version on Linux 3.13.0-76-generic (x86_64)
Not in a repository:
flashrom unknown version on Linux 3.13.0-76-generic (x86_64)
Signed-off-by: Stefan Tauner <stefan.tauner(a)alumni.tuwien.ac.at>
Acked-by: Stefan Tauner <stefan.tauner(a)alumni.tuwien.ac.at>
This is the 2nd commit message:
Use standard git commit-msg hook
This replaces commit-msg hook with the standard one so that
Change-Ids are generated.
We could merge the one which was being used which detects multiple
lines beginning with "Signed-off-by", however I wanted to check with
the author first due to licensing of the standard hook (Apache 2.0).
Change-Id: I8d3f54c3e87d3875b73a6f24c15d2ae43b84819f
Signed-off-by: David Hendricks <dhendricks(a)fb.com>
---
A .gitattributes
A .gitignore
M Makefile
M flashrom.c
M util/getrevision.sh
A util/git-hooks/applypatch-msg
A util/git-hooks/commit-msg
A util/git-hooks/install.sh
A util/git-hooks/pre-applypatch
A util/git-hooks/pre-commit
A util/git-hooks/pre-push
A util/git-hooks/wrapper.sh
12 files changed, 562 insertions(+), 124 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/85/19185/2
--
To view, visit https://review.coreboot.org/19185
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I8d3f54c3e87d3875b73a6f24c15d2ae43b84819f
Gerrit-PatchSet: 2
Gerrit-Project: flashrom
Gerrit-Branch: staging
Gerrit-Owner: David Hendricks <david.hendricks(a)gmail.com>