summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-08-21 18:34:04 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-08-31 05:22:46 -0700
commit09c1c22dff11a588e9f27c57c4574930f2e168dd (patch)
tree782d7f4f3b680001084906ab071c8a74be7b36c3
parent8c3a895e7f7ecef9147ffd8b421626db97216d6f (diff)
downloadvboot-09c1c22dff11a588e9f27c57c4574930f2e168dd.tar.gz
futility: cmd_update: Access system firmware using external flashrom
To manipulate the firmware contents on device, we need to access the flash chipset (usually via SPI) on system. The `host_flashrom` provides a way to call external program "flashrom" for reading and writing firmware. So the `update_firmware` can now load "system current firmware" using flashrom. Note in the future we may want to statically link the flashrom as library so there won't be external dependency. BUG=chromium:875551 TEST=make futil; futility update -i IMAGE tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: I52f2d4fe4fe4dd660f762a5a75e3367820717e19 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1183650 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--futility/cmd_update.c98
-rwxr-xr-xtests/futility/test_update.sh6
2 files changed, 100 insertions, 4 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index 5c724731..0ddaa01b 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -16,6 +16,8 @@
#include "host_misc.h"
#include "utility.h"
+#define RETURN_ON_FAILURE(x) do {int r = (x); if (r) return r;} while (0);
+
/* FMAP section names. */
static const char * const FMAP_RO_FRID = "RO_FRID",
* const FMAP_RW_FWID = "RW_FWID",
@@ -27,6 +29,11 @@ static const char * const PROG_HOST = "host",
* const PROG_EC = "ec",
* const PROG_PD = "ec:dev=1";
+enum flashrom_ops {
+ FLASHROM_READ,
+ FLASHROM_WRITE,
+};
+
struct firmware_image {
const char *programmer;
uint32_t size;
@@ -47,6 +54,64 @@ struct updater_config {
};
/*
+ * A helper function to invoke flashrom(8) command.
+ * Returns 0 if success, non-zero if error.
+ */
+static int host_flashrom(enum flashrom_ops op, const char *image_path,
+ const char *programmer, int verbose,
+ const char *section_name)
+{
+ char *command;
+ const char *op_cmd, *dash_i = "-i", *postfix = "";
+ int r;
+
+ if (debugging_enabled)
+ verbose = 1;
+
+ if (!verbose)
+ postfix = " >/dev/null 2>&1";
+
+ if (!section_name || !*section_name) {
+ dash_i = "";
+ section_name = "";
+ }
+
+ switch (op) {
+ case FLASHROM_READ:
+ op_cmd = "-r";
+ assert(image_path);
+ break;
+
+ case FLASHROM_WRITE:
+ op_cmd = "-w";
+ assert(image_path);
+ break;
+
+ default:
+ assert(0);
+ return -1;
+ }
+
+ /* TODO(hungte) In future we should link with flashrom directly. */
+ r = asprintf(&command, "flashrom %s %s -p %s %s %s %s", op_cmd,
+ image_path, programmer, dash_i, section_name, postfix);
+
+ if (r == -1) {
+ /* `command` will be not available. */
+ Error("%s: Cannot allocate memory for command to execute.\n",
+ __FUNCTION__);
+ return -1;
+ }
+
+ if (verbose)
+ printf("Executing: %s\n", command);
+
+ r = system(command);
+ free(command);
+ return r;
+}
+
+/*
* Finds a firmware section by given name in the firmware image.
* If successful, return zero and *section argument contains the address and
* size of the section; otherwise failure.
@@ -147,6 +212,21 @@ static int load_image(const char *file_name, struct firmware_image *image)
}
/*
+ * Loads the active system firmware image (usually from SPI flash chip).
+ * Returns 0 if success, non-zero if error.
+ */
+static int load_system_image(struct updater_config *cfg,
+ struct firmware_image *image)
+{
+ /* TODO(hungte) replace by mkstemp */
+ const char *tmp_file = "/tmp/.fwupdate.read";
+
+ RETURN_ON_FAILURE(host_flashrom(
+ FLASHROM_READ, tmp_file, image->programmer, 0, NULL));
+ return load_image(tmp_file, image);
+}
+
+/*
* Frees the allocated resource from a firmware image object.
*/
static void free_image(struct firmware_image *image)
@@ -162,12 +242,14 @@ static void free_image(struct firmware_image *image)
enum updater_error_codes {
UPDATE_ERR_DONE,
UPDATE_ERR_NO_IMAGE,
+ UPDATE_ERR_SYSTEM_IMAGE,
UPDATE_ERR_UNKNOWN,
};
static const char * const updater_error_messages[] = {
[UPDATE_ERR_DONE] = "Done (no error)",
[UPDATE_ERR_NO_IMAGE] = "No image to update; try specify with -i.",
+ [UPDATE_ERR_SYSTEM_IMAGE] = "Cannot load system active firmware.",
[UPDATE_ERR_UNKNOWN] = "Unknown error.",
};
@@ -177,7 +259,8 @@ static const char * const updater_error_messages[] = {
*/
static enum updater_error_codes update_firmware(struct updater_config *cfg)
{
- struct firmware_image *image_to = &cfg->image;
+ struct firmware_image *image_from = &cfg->image_current,
+ *image_to = &cfg->image;
if (!image_to->data)
return UPDATE_ERR_NO_IMAGE;
@@ -185,6 +268,19 @@ static enum updater_error_codes update_firmware(struct updater_config *cfg)
image_to->file_name, image_to->ro_version,
image_to->rw_version_a, image_to->rw_version_b);
+ if (!image_from->data) {
+ /*
+ * TODO(hungte) Read only RO_SECTION, VBLOCK_A, VBLOCK_B,
+ * RO_VPD, RW_VPD, RW_NVRAM, RW_LEGACY.
+ */
+ printf("Loading current system firmware...\n");
+ if (load_system_image(cfg, image_from) != 0)
+ return UPDATE_ERR_SYSTEM_IMAGE;
+ }
+ printf(">> Current system: %s (RO:%s, RW/A:%s, RW/B:%s).\n",
+ image_from->file_name, image_from->ro_version,
+ image_from->rw_version_a, image_from->rw_version_b);
+
return UPDATE_ERR_DONE;
}
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index c7ade51a..aaf46904 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -16,6 +16,6 @@ cd "$OUTDIR"
set -o pipefail
# Test command execution.
-"${FUTILITY}" update -i "${LINK_BIOS}" |
- grep "RO:${LINK_VERSION}, RW/A:${LINK_VERSION}, RW/B:${LINK_VERSION}"
-"${FUTILITY}" --debug update -i "${LINK_BIOS}" | grep 8388608
+
+# The updater is now currently always loading system firmware using flashrom(8)
+# and can't be tested until an emulation interface is implemented.