diff options
Diffstat (limited to 'host/lib/flashrom_drv.c')
-rw-r--r-- | host/lib/flashrom_drv.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/host/lib/flashrom_drv.c b/host/lib/flashrom_drv.c new file mode 100644 index 00000000..02250472 --- /dev/null +++ b/host/lib/flashrom_drv.c @@ -0,0 +1,190 @@ +/* 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" +#include "../../futility/futility.h" +#include "flashrom.h" + +// 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, const char *region, + 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 (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); + } + + image->data = calloc(1, len); + image->size = len; + image->file_name = strdup("<none>"); + + r |= flashrom_image_read(flashctx, image->data, len); + +err_cleanup: + r |= flashrom_programmer_shutdown(prog); + flashrom_layout_release(layout); + 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 do_verify, 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 (!do_verify) + 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; +} |