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/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>