diff options
author | Edward O'Callaghan <quasisec@google.com> | 2021-12-21 11:03:53 +1100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-12-24 00:50:51 +0000 |
commit | b9859822af4a709e344607fce987a6ef2a75ac75 (patch) | |
tree | 4005d4f5a8513164736c402ded1f4e0894334674 | |
parent | f2c41528b1324c9c546e0b59b73bfe6e3b98e7b7 (diff) | |
download | vboot-b9859822af4a709e344607fce987a6ef2a75ac75.tar.gz |
vboot_ref/futility: Extract out flashrom call logic
Separate out all the flashrom worker code used in futility
to allow for later building a futility without flashrom
support.
BUG=b:203715651,b:209702505
BRANCH=none
TEST=builds
Signed-off-by: Edward O'Callaghan <quasisec@google.com>
Change-Id: I938141056424f8f93a598bbb288ee7c8770edc95
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3350298
Tested-by: Edward O'Callaghan <quasisec@chromium.org>
Auto-Submit: Edward O'Callaghan <quasisec@chromium.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Commit-Queue: Edward O'Callaghan <quasisec@chromium.org>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | futility/flashrom_drv.c | 197 | ||||
-rw-r--r-- | futility/updater.c | 2 | ||||
-rw-r--r-- | futility/updater_utils.c | 197 | ||||
-rw-r--r-- | futility/updater_utils.h | 8 |
5 files changed, 216 insertions, 191 deletions
@@ -665,7 +665,8 @@ FUTIL_SRCS = \ futility/updater_quirks.c \ futility/updater_utils.c \ futility/vb1_helper.c \ - futility/vb2_helper.c + futility/vb2_helper.c \ + futility/flashrom_drv.c # List of commands built in futility. FUTIL_CMD_LIST = ${BUILD}/gen/futility_cmds.c diff --git a/futility/flashrom_drv.c b/futility/flashrom_drv.c new file mode 100644 index 00000000..5ebe4468 --- /dev/null +++ b/futility/flashrom_drv.c @@ -0,0 +1,197 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * The utility functions for firmware updater. + */ + +#include <libflashrom.h> + +#include "2common.h" +#include "crossystem.h" +#include "host_misc.h" +#include "util_misc.h" +#include "updater.h" + +#define FLASHROM_OUTPUT_WP_PATTERN "write protect is " + +/* System environment values. */ +static const char * const FLASHROM_OUTPUT_WP_ENABLED = + FLASHROM_OUTPUT_WP_PATTERN "enabled", + * const FLASHROM_OUTPUT_WP_DISABLED = + FLASHROM_OUTPUT_WP_PATTERN "disabled"; + +// global to allow verbosity level to be injected into callback. +static enum flashrom_log_level g_verbose_screen = FLASHROM_MSG_INFO; + +static int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, + va_list ap) +{ + int ret = 0; + FILE *output_type = (level < FLASHROM_MSG_INFO) ? stderr : stdout; + + if (level > g_verbose_screen) + return ret; + + ret = vfprintf(output_type, fmt, ap); + /* msg_*spew often happens inside chip accessors + * in possibly time-critical operations. + * Don't slow them down by flushing. + */ + if (level != FLASHROM_MSG_SPEW) + fflush(output_type); + + return ret; +} + +static char *flashrom_extract_params(const char *str, char **prog, char **params) +{ + char *tmp = strdup(str); + *prog = strtok(tmp, ":"); + *params = strtok(NULL, ""); + return tmp; +} + +int flashrom_read_image(struct firmware_image *image, int verbosity) +{ + int r = 0; + size_t len = 0; + + g_verbose_screen = verbosity; + + char *programmer, *params; + char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms); + + struct flashrom_programmer *prog = NULL; + struct flashrom_flashctx *flashctx = NULL; + + flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb); + + r |= flashrom_init(1); + r |= flashrom_programmer_init(&prog, programmer, params); + r |= flashrom_flash_probe(&flashctx, prog, NULL); + + len = flashrom_flash_getsize(flashctx); + image->data = calloc(1, len); + image->size = len; + image->file_name = strdup("<none>"); + + r |= flashrom_image_read(flashctx, image->data, len); + + r |= flashrom_programmer_shutdown(prog); + flashrom_flash_release(flashctx); + free(tmp); + + return r; +} + +int flashrom_write_image(const struct firmware_image *image, + const char *region, + const struct firmware_image *diff_image, + int verbosity) +{ + int r = 0; + size_t len = 0; + + g_verbose_screen = verbosity; + + char *programmer, *params; + char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms); + + struct flashrom_programmer *prog = NULL; + struct flashrom_flashctx *flashctx = NULL; + struct flashrom_layout *layout = NULL; + + flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb); + + r |= flashrom_init(1); + r |= flashrom_programmer_init(&prog, programmer, params); + r |= flashrom_flash_probe(&flashctx, prog, NULL); + + len = flashrom_flash_getsize(flashctx); + if (len == 0) { + ERROR("zero sized flash detected\n"); + r = -1; + goto err_cleanup; + } + + if (diff_image) { + if (diff_image->size != image->size) { + ERROR("diff_image->size != image->size"); + r = -1; + goto err_cleanup; + } + } + + if (region) { + r = flashrom_layout_read_fmap_from_buffer( + &layout, flashctx, (const uint8_t *)image->data, + image->size); + if (r > 0) { + WARN("could not read fmap from image, r=%d, " + "falling back to read from rom\n", r); + r = flashrom_layout_read_fmap_from_rom( + &layout, flashctx, 0, len); + if (r > 0) { + ERROR("could not read fmap from rom, r=%d\n", r); + r = -1; + 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; + } + flashrom_layout_set(flashctx, layout); + } + + flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, true); + flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true); + if (diff_image) /* equiv --noverify --flash-contents=diff_image at cli */ + flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, false); + + r |= flashrom_image_write(flashctx, image->data, image->size, + diff_image ? diff_image->data : NULL); + +err_cleanup: + r |= flashrom_programmer_shutdown(prog); + flashrom_layout_release(layout); + flashrom_flash_release(flashctx); + free(tmp); + + return r; +} + +/* Helper function to return write protection status via given programmer. */ +enum wp_state flashrom_get_wp(const char *programmer) +{ + char *command, *result; + const char *postfix; + int r; + + /* grep is needed because host_shell only returns 1 line. */ + postfix = " 2>/dev/null | grep \"" FLASHROM_OUTPUT_WP_PATTERN "\""; + + + /* TODO(b/203715651): link with flashrom directly. */ + ASPRINTF(&command, "flashrom --wp-status -p %s %s", programmer, postfix); + + /* invokes flashrom(8) with non-zero result if error. */ + result = host_shell(command); + strip_string(result, NULL); + free(command); + VB2_DEBUG("wp-status: %s\n", result); + + if (strstr(result, FLASHROM_OUTPUT_WP_ENABLED)) + r = WP_ENABLED; + else if (strstr(result, FLASHROM_OUTPUT_WP_DISABLED)) + r = WP_DISABLED; + else + r = WP_ERROR; + free(result); + + return r; +} diff --git a/futility/updater.c b/futility/updater.c index 8b1c1555..b550b33c 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -458,7 +458,7 @@ static int write_optional_firmware(struct updater_config *cfg, */ if (check_programmer_wp && get_system_property(SYS_PROP_WP_HW, cfg) == WP_ENABLED && - host_get_wp(image->programmer) == WP_ENABLED) { + flashrom_get_wp(image->programmer) == WP_ENABLED) { ERROR("Target %s is write protected, skip updating.\n", image->programmer); return 0; diff --git a/futility/updater_utils.c b/futility/updater_utils.c index 503747ac..936abaf3 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c @@ -15,8 +15,6 @@ #include <sys/wait.h> #endif -#include <libflashrom.h> - #include "2common.h" #include "crossystem.h" #include "host_misc.h" @@ -24,14 +22,9 @@ #include "updater.h" #define COMMAND_BUFFER_SIZE 256 -#define FLASHROM_OUTPUT_WP_PATTERN "write protect is " /* System environment values. */ -static const char * const STR_REV = "rev", - * const FLASHROM_OUTPUT_WP_ENABLED = - FLASHROM_OUTPUT_WP_PATTERN "enabled", - * const FLASHROM_OUTPUT_WP_DISABLED = - FLASHROM_OUTPUT_WP_PATTERN "disabled"; +static const char * const STR_REV = "rev"; /* * Strips a string (usually from shell execution output) by removing all the @@ -522,182 +515,6 @@ char *host_detect_servo(int *need_prepare_ptr) return ret; } -// global to allow verbosity level to be injected into callback. -static enum flashrom_log_level g_verbose_screen = FLASHROM_MSG_INFO; - -static int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, - va_list ap) -{ - int ret = 0; - FILE *output_type = (level < FLASHROM_MSG_INFO) ? stderr : stdout; - - if (level > g_verbose_screen) - return ret; - - ret = vfprintf(output_type, fmt, ap); - /* msg_*spew often happens inside chip accessors - * in possibly time-critical operations. - * Don't slow them down by flushing. - */ - if (level != FLASHROM_MSG_SPEW) - fflush(output_type); - - return ret; -} - -static char *flashrom_extract_params(const char *str, char **prog, char **params) -{ - char *tmp = strdup(str); - *prog = strtok(tmp, ":"); - *params = strtok(NULL, ""); - return tmp; -} - -static int host_flashrom_read(struct firmware_image *image) -{ - int r = 0; - size_t len = 0; - - char *programmer, *params; - char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms); - - struct flashrom_programmer *prog = NULL; - struct flashrom_flashctx *flashctx = NULL; - - flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb); - - r |= flashrom_init(1); - r |= flashrom_programmer_init(&prog, programmer, params); - r |= flashrom_flash_probe(&flashctx, prog, NULL); - - len = flashrom_flash_getsize(flashctx); - image->data = calloc(1, len); - image->size = len; - image->file_name = strdup("<none>"); - - r |= flashrom_image_read(flashctx, image->data, len); - - r |= flashrom_programmer_shutdown(prog); - flashrom_flash_release(flashctx); - free(tmp); - - return r; -} - -static int host_flashrom_write(const struct firmware_image *image, - const char *region, - const struct firmware_image *diff_image) -{ - int r = 0; - size_t len = 0; - - char *programmer, *params; - char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms); - - struct flashrom_programmer *prog = NULL; - struct flashrom_flashctx *flashctx = NULL; - struct flashrom_layout *layout = NULL; - - flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb); - - r |= flashrom_init(1); - r |= flashrom_programmer_init(&prog, programmer, params); - r |= flashrom_flash_probe(&flashctx, prog, NULL); - - len = flashrom_flash_getsize(flashctx); - if (len == 0) { - ERROR("zero sized flash detected\n"); - r = -1; - goto err_cleanup; - } - - if (diff_image) { - if (diff_image->size != image->size) { - ERROR("diff_image->size != image->size"); - r = -1; - goto err_cleanup; - } - } - - if (region) { - r = flashrom_layout_read_fmap_from_buffer( - &layout, flashctx, (const uint8_t *)image->data, - image->size); - if (r > 0) { - WARN("could not read fmap from image, r=%d, " - "falling back to read from rom\n", r); - r = flashrom_layout_read_fmap_from_rom( - &layout, flashctx, 0, len); - if (r > 0) { - ERROR("could not read fmap from rom, r=%d\n", r); - r = -1; - 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; - } - flashrom_layout_set(flashctx, layout); - } - - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, true); - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true); - if (diff_image) /* equiv --noverify --flash-contents=diff_image at cli */ - flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, false); - - r |= flashrom_image_write(flashctx, image->data, image->size, - diff_image ? diff_image->data : NULL); - -err_cleanup: - r |= flashrom_programmer_shutdown(prog); - flashrom_layout_release(layout); - flashrom_flash_release(flashctx); - free(tmp); - - return r; -} - -/* Helper function to return write protection status via given programmer. */ -enum wp_state host_get_wp(const char *programmer) -{ - char *command, *result; - const char *postfix; - int r; - - /* grep is needed because host_shell only returns 1 line. */ - postfix = " 2>/dev/null | grep \"" FLASHROM_OUTPUT_WP_PATTERN "\""; - - - /* TODO(b/203715651): link with flashrom directly. */ - ASPRINTF(&command, "flashrom --wp-status -p %s %s", programmer, postfix); - - /* invokes flashrom(8) with non-zero result if error. */ - result = host_shell(command); - strip_string(result, NULL); - free(command); - VB2_DEBUG("wp-status: %s\n", result); - - if (strstr(result, FLASHROM_OUTPUT_WP_ENABLED)) - r = WP_ENABLED; - else if (strstr(result, FLASHROM_OUTPUT_WP_DISABLED)) - r = WP_DISABLED; - else - r = WP_ERROR; - free(result); - - return r; -} - -/* Helper function to return host software write protection status. */ -static int host_get_wp_sw(void) -{ - return host_get_wp(PROG_HOST); -} - /* * Loads the active system firmware image (usually from SPI flash chip). * Returns 0 if success, non-zero if error. @@ -707,8 +524,7 @@ int load_system_firmware(struct firmware_image *image, { int r; - g_verbose_screen = verbosity + 1; - r = host_flashrom_read(image); + r = flashrom_read_image(image, (verbosity + 1)); if (!r) r = parse_firmware_image(image); return r; @@ -725,8 +541,13 @@ int write_system_firmware(const struct firmware_image *image, struct tempfile *tempfiles, int verbosity) { - g_verbose_screen = verbosity + 1; - return host_flashrom_write(image, section_name, diff_image); + return flashrom_write_image(image, section_name, diff_image, (verbosity + 1)); +} + +/* Helper function to return host software write protection status. */ +static int host_get_wp_sw(void) +{ + return flashrom_get_wp(PROG_HOST); } /* Helper function to configure all properties. */ diff --git a/futility/updater_utils.h b/futility/updater_utils.h index 25316757..2d64c295 100644 --- a/futility/updater_utils.h +++ b/futility/updater_utils.h @@ -175,7 +175,7 @@ enum wp_state { }; /* Helper function to return write protection status via given programmer. */ -enum wp_state host_get_wp(const char *programmer); +enum wp_state flashrom_get_wp(const char *programmer); /* The environment variable name for setting servod port. */ #define ENV_SERVOD_PORT "SERVOD_PORT" @@ -228,4 +228,10 @@ void init_system_properties(struct system_property *props, int num); */ const char *get_firmware_rootkey_hash(const struct firmware_image *image); +int flashrom_read_image(struct firmware_image *image, int verbosity); +int flashrom_write_image(const struct firmware_image *image, + const char *region, + const struct firmware_image *diff_image, + int verbosity); + #endif /* VBOOT_REFERENCE_FUTILITY_UPDATER_UTILS_H_ */ |