summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2022-02-25 11:27:54 +0800
committerCommit Bot <commit-bot@chromium.org>2022-03-01 02:41:41 +0000
commitcc3f48ba5dc64e91404fccdec100f6c67887b01a (patch)
tree355d61887d2935459ee87cb64a06329f189c53dd
parent07a7bc69641129e937ab702b95e893d4a5ba45fd (diff)
downloadvboot-cc3f48ba5dc64e91404fccdec100f6c67887b01a.tar.gz
futility: flashrom_drv: support partial write for multiple regions
When we have multiple regions to update, invoking flashrom_write_image multiple times will take much longer because for each write it has to read the whole flash, write and then verify whole flash (also timer calibration and programmer init/shutdown every time). As a result, we want to support writing multiple regions - just like that flashrom can take arbitrary numbers of "-i REGION". This change only extended flashrom_write_image, and the firmware updater is calling flashrom_drv multiple times. That will be addressed in the follow up changes. BUG=b:221137867 TEST=build; and run test BRANCH=None Signed-off-by: Hung-Te Lin <hungte@chromium.org> Change-Id: Id335cc9f816f1384f1886422efa97fe2c7b81aec Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3490388 Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
-rw-r--r--futility/updater.c6
-rw-r--r--futility/updater_utils.c36
-rw-r--r--futility/updater_utils.h7
-rw-r--r--host/lib/flashrom_drv.c20
-rw-r--r--host/lib/include/flashrom.h7
5 files changed, 52 insertions, 24 deletions
diff --git a/futility/updater.c b/futility/updater.c
index bc68040e..021916a6 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -420,6 +420,9 @@ static int write_firmware(struct updater_config *cfg,
const char *section_name)
{
struct firmware_image *diff_image = NULL;
+ const char *sections[2] = {0};
+
+ sections[0] = section_name;
if (cfg->emulation) {
INFO("(emulation) Writing %s from %s to %s (emu=%s).\n",
@@ -434,7 +437,8 @@ static int write_firmware(struct updater_config *cfg,
is_the_same_programmer(&cfg->image_current, image))
diff_image = &cfg->image_current;
- return write_system_firmware(image, diff_image, section_name,
+ return write_system_firmware(image, diff_image,
+ section_name ? sections : NULL,
&cfg->tempfiles, cfg->do_verify,
get_io_retries(cfg), cfg->verbosity + 1);
}
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 9f91129e..18e40000 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -543,31 +543,49 @@ int load_system_firmware(struct firmware_image *image,
}
/*
- * Writes a section from given firmware image to system firmware.
- * If section_name is NULL, write whole image.
+ * Writes sections from a given firmware image to the system firmware.
+ * Regions should be NULL for writing the whole image, or a list of
+ * FMAP section names (and ended with a NULL).
* Returns 0 if success, non-zero if error.
*/
int write_system_firmware(const struct firmware_image *image,
const struct firmware_image *diff_image,
- const char *section_name,
+ const char * const sections[],
struct tempfile *tempfiles,
int do_verify, int retries, int verbosity)
{
- int r, i;
+ int r, i, len = 0;
+ char *partial = NULL;
+
+ for (i = 0; sections && sections[i]; i++)
+ len += strlen(sections[i]) + strlen(" -i ");
+ if (len) {
+ partial = (char *)malloc(len + 1);
+ if (!partial) {
+ ERROR("Failed to allocate a string buffer.\n");
+ return -1;
+ }
+ partial[0] = '\0';
+ for (i = 0; sections[i]; i++) {
+ strcat(partial, " -i ");
+ strcat(partial, sections[i]);
+ }
+ assert(strlen(partial) == len);
+ }
- INFO("flashrom -w <IMAGE> -p %s%s%s%s%s%s\n",
+ INFO("flashrom -w <IMAGE> -p %s%s%s%s%s\n",
image->programmer,
diff_image ? " --flash-contents <DIFF_IMAGE>" : "",
do_verify ? "" : " --noverify",
verbosity > 1 ? " -V" : "",
- section_name ? " -i " : "",
- section_name ? section_name : "");
+ partial ? partial : "");
+ free(partial);
for (i = 1, r = -1; i <= retries && r != 0; i++) {
if (i > 1)
WARN("Retry writing firmware (%d/%d)...\n", i, retries);
- r = flashrom_write_image(image, section_name, diff_image,
- do_verify, verbosity + 1);
+ r = flashrom_write_image(image, sections, diff_image, do_verify,
+ verbosity + 1);
/*
* Force a newline to flush stdout in case if
* flashrom_write_image left some messages in the buffer.
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index 4ab61c93..3eb1d33c 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -93,13 +93,14 @@ const char *get_firmware_image_temp_file(const struct firmware_image *image,
struct tempfile *tempfiles);
/*
- * Writes a section from given firmware image to system firmware.
- * If section_name is NULL, write whole image.
+ * Writes sections from a given firmware image to the system firmware.
+ * Regions should be NULL for writing the whole image, or a list of
+ * FMAP section names (and ended with a NULL).
* Returns 0 if success, non-zero if error.
*/
int write_system_firmware(const struct firmware_image *image,
const struct firmware_image *diff_image,
- const char *section_name,
+ const char * const sections[],
struct tempfile *tempfiles,
int do_verify, int retries, int verbosity);
diff --git a/host/lib/flashrom_drv.c b/host/lib/flashrom_drv.c
index 18e00ebe..1d9e3fd9 100644
--- a/host/lib/flashrom_drv.c
+++ b/host/lib/flashrom_drv.c
@@ -119,7 +119,7 @@ err_init:
}
int flashrom_write_image(const struct firmware_image *image,
- const char *region,
+ const char * const regions[],
const struct firmware_image *diff_image,
int do_verify, int verbosity)
{
@@ -162,7 +162,8 @@ int flashrom_write_image(const struct firmware_image *image,
}
}
- if (region) {
+ if (regions) {
+ int i;
r = flashrom_layout_read_fmap_from_buffer(
&layout, flashctx, (const uint8_t *)image->data,
image->size);
@@ -177,12 +178,15 @@ int flashrom_write_image(const struct firmware_image *image,
goto err_cleanup;
}
}
- // empty region causes seg fault in API.
- r |= flashrom_layout_include_region(layout, region);
- if (r > 0) {
- ERROR("could not include region = '%s'\n", region);
- r = -1;
- goto err_cleanup;
+ for (i = 0; regions[i]; i++) {
+ // empty region causes seg fault in API.
+ r |= flashrom_layout_include_region(layout, regions[i]);
+ if (r > 0) {
+ ERROR("could not include region = '%s'\n",
+ regions[i]);
+ r = -1;
+ goto err_cleanup;
+ }
}
flashrom_layout_set(flashctx, layout);
}
diff --git a/host/lib/include/flashrom.h b/host/lib/include/flashrom.h
index eb6d5313..6058d644 100644
--- a/host/lib/include/flashrom.h
+++ b/host/lib/include/flashrom.h
@@ -48,13 +48,14 @@ int flashrom_read_image(struct firmware_image *image, const char *region,
*
* @param image The parameter that contains the programmer, buffer and
* size to use in the write operation.
- * @param region The name of the fmap region to write, or NULL to
- * write the entire flash chip.
+ * @param regions A list of the names of the fmap regions to write, or
+ * NULL to write the entire flash chip. The list must be
+ * ended with a NULL pointer.
*
* @return VB2_SUCCESS on success, or a relevant error.
*/
vb2_error_t flashrom_write(struct firmware_image *image, const char *region);
int flashrom_write_image(const struct firmware_image *image,
- const char *region,
+ const char * const regions[],
const struct firmware_image *diff_image,
int do_verify, int verbosity);