diff --git a/cli_classic.c b/cli_classic.c index 441fc919c..31f7394d4 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -60,6 +60,7 @@ static void cli_classic_usage(const char *name) " --ifd read layout from an Intel Firmware Descriptor\n" " -i | --image only flash image from flash layout\n" " -o | --output log output to \n" + " --flash-contents assume flash contents to be \n" " -L | --list-supported print supported devices\n" #if CONFIG_PRINT_WIKI == 1 " -z | --list-supported-wiki print supported devices in wiki syntax\n" @@ -108,6 +109,10 @@ int main(int argc, char *argv[]) int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0; struct flashrom_layout *layout = NULL; enum programmer prog = PROGRAMMER_INVALID; + enum { + OPTION_IFD = 0x0100, + OPTION_FLASH_CONTENTS, + }; int ret = 0; static const char optstring[] = "r:Rw:v:nNVEfc:l:i:p:Lzho:"; @@ -122,8 +127,9 @@ int main(int argc, char *argv[]) {"verbose", 0, NULL, 'V'}, {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, - {"ifd", 0, NULL, 0x0100}, + {"ifd", 0, NULL, OPTION_IFD}, {"image", 1, NULL, 'i'}, + {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS}, {"list-supported", 0, NULL, 'L'}, {"list-supported-wiki", 0, NULL, 'z'}, {"programmer", 1, NULL, 'p'}, @@ -134,6 +140,7 @@ int main(int argc, char *argv[]) }; char *filename = NULL; + char *referencefile = NULL; char *layoutfile = NULL; #ifndef STANDALONE char *logfile = NULL; @@ -229,7 +236,7 @@ int main(int argc, char *argv[]) } layoutfile = strdup(optarg); break; - case 0x0100: + case OPTION_IFD: if (layoutfile) { fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); cli_classic_abort_usage(); @@ -243,6 +250,9 @@ int main(int argc, char *argv[]) cli_classic_abort_usage(); } break; + case OPTION_FLASH_CONTENTS: + referencefile = strdup(optarg); + break; case 'L': if (++operation_specified > 1) { fprintf(stderr, "More than one operation " @@ -354,6 +364,9 @@ int main(int argc, char *argv[]) if (layoutfile && check_filename(layoutfile, "layout")) { cli_classic_abort_usage(); } + if (referencefile && check_filename(referencefile, "reference")) { + cli_classic_abort_usage(); + } #ifndef STANDALONE if (logfile && check_filename(logfile, "log")) @@ -569,7 +582,7 @@ int main(int argc, char *argv[]) else if (erase_it) ret = do_erase(fill_flash); else if (write_it) - ret = do_write(fill_flash, filename); + ret = do_write(fill_flash, filename, referencefile); else if (verify_it) ret = do_verify(fill_flash, filename); @@ -583,6 +596,7 @@ out: layout_cleanup(); free(filename); + free(referencefile); free(layoutfile); free(pparam); /* clean up global variables */ diff --git a/flash.h b/flash.h index 7bf3cc714..a80a9c249 100644 --- a/flash.h +++ b/flash.h @@ -329,7 +329,7 @@ int prepare_flash_access(struct flashctx *, bool read_it, bool write_it, bool er void finalize_flash_access(struct flashctx *); int do_read(struct flashctx *, const char *filename); int do_erase(struct flashctx *); -int do_write(struct flashctx *, const char *const filename); +int do_write(struct flashctx *, const char *const filename, const char *const referencefile); int do_verify(struct flashctx *, const char *const filename); /* Something happened that shouldn't happen, but we can go on. */ diff --git a/flashrom.c b/flashrom.c index 26b9863c8..d87a43171 100644 --- a/flashrom.c +++ b/flashrom.c @@ -2345,13 +2345,15 @@ static void combine_image_by_layout(const struct flashctx *const flashctx, * @param flashctx The context of the flash chip. * @param buffer Source buffer to read image from (may be altered for full verification). * @param buffer_len Size of source buffer in bytes. + * @param refbuffer If given, assume flash chip contains same data as `refbuffer`. * @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 flashrom_image_write(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len) +int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len, + const void *const refbuffer) { const size_t flash_size = flashctx->chip->total_size * 1024; const bool verify_all = flashctx->flags.verify_whole_chip; @@ -2363,6 +2365,7 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co int ret = 1; uint8_t *const newcontents = buffer; + const uint8_t *const refcontents = refbuffer; uint8_t *const curcontents = malloc(flash_size); uint8_t *oldcontents = NULL; if (verify_all) @@ -2387,27 +2390,35 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co 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 _finalize_ret; - } - memcpy(curcontents, oldcontents, flash_size); + /* If given, assume flash chip contains same data as `refcontents`. */ + if (refcontents) { + msg_cinfo("Assuming old flash chip contents as ref-file...\n"); + memcpy(curcontents, refcontents, flash_size); + if (oldcontents) + memcpy(oldcontents, refcontents, flash_size); } else { - if (read_by_layout(flashctx, curcontents)) { - msg_cinfo("FAILED.\n"); - goto _finalize_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 _finalize_ret; + } + memcpy(curcontents, oldcontents, flash_size); + } else { + if (read_by_layout(flashctx, curcontents)) { + msg_cinfo("FAILED.\n"); + goto _finalize_ret; + } } + msg_cinfo("done.\n"); } - msg_cinfo("done.\n"); if (write_by_layout(flashctx, curcontents, newcontents)) { msg_cerr("Uh oh. Erase/write failed. "); @@ -2542,13 +2553,15 @@ int do_erase(struct flashctx *const flash) return ret; } -int do_write(struct flashctx *const flash, const char *const filename) +int do_write(struct flashctx *const flash, const char *const filename, const char *const referencefile) { const size_t flash_size = flash->chip->total_size * 1024; int ret = 1; uint8_t *const newcontents = malloc(flash_size); - if (!newcontents) { + uint8_t *const refcontents = referencefile ? malloc(flash_size) : NULL; + + if (!newcontents || (referencefile && !refcontents)) { msg_gerr("Out of memory!\n"); goto _free_ret; } @@ -2556,9 +2569,15 @@ int do_write(struct flashctx *const flash, const char *const filename) if (read_buf_from_file(newcontents, flash_size, filename)) goto _free_ret; - ret = flashrom_image_write(flash, newcontents, flash_size); + if (referencefile) { + if (read_buf_from_file(refcontents, flash_size, referencefile)) + goto _free_ret; + } + + ret = flashrom_image_write(flash, newcontents, flash_size, refcontents); _free_ret: + free(refcontents); free(newcontents); return ret; } diff --git a/libflashrom.h b/libflashrom.h index d3f3dedcf..786147b2d 100644 --- a/libflashrom.h +++ b/libflashrom.h @@ -60,7 +60,7 @@ void flashrom_flag_set(struct flashrom_flashctx *, enum flashrom_flag, bool valu bool flashrom_flag_get(const struct flashrom_flashctx *, enum flashrom_flag); int flashrom_image_read(struct flashrom_flashctx *, void *buffer, size_t buffer_len); -int flashrom_image_write(struct flashrom_flashctx *, void *buffer, size_t buffer_len); +int flashrom_image_write(struct flashrom_flashctx *, void *buffer, size_t buffer_len, const void *refbuffer); int flashrom_image_verify(struct flashrom_flashctx *, const void *buffer, size_t buffer_len); struct flashrom_layout; @@ -69,4 +69,4 @@ int flashrom_layout_include_region(struct flashrom_layout *, const char *name); void flashrom_layout_release(struct flashrom_layout *); void flashrom_layout_set(struct flashrom_flashctx *, const struct flashrom_layout *); -#endif /* !__LIBFLASHROM_H__ */ +#endif /* !__LIBFLASHROM_H__ */ \ No newline at end of file