diff options
-rw-r--r-- | 82802ab.c | 1 | ||||
-rw-r--r-- | at45db.c | 1 | ||||
-rw-r--r-- | cli_classic.c | 14 | ||||
-rw-r--r-- | cli_output.c | 25 | ||||
-rw-r--r-- | dediprog.c | 1 | ||||
-rw-r--r-- | en29lv640b.c | 1 | ||||
-rw-r--r-- | flashrom.8.tmpl | 6 | ||||
-rw-r--r-- | include/flash.h | 5 | ||||
-rw-r--r-- | include/libflashrom.h | 29 | ||||
-rw-r--r-- | it87spi.c | 1 | ||||
-rw-r--r-- | jedec.c | 5 | ||||
-rw-r--r-- | libflashrom.c | 19 | ||||
-rw-r--r-- | libflashrom.map | 1 | ||||
-rw-r--r-- | linux_mtd.c | 3 | ||||
-rw-r--r-- | lspcon_i2c_spi.c | 2 | ||||
-rw-r--r-- | realtek_mst_i2c_spi.c | 1 | ||||
-rw-r--r-- | spi.c | 3 | ||||
-rw-r--r-- | spi25.c | 7 | ||||
-rw-r--r-- | sst28sf040.c | 1 | ||||
-rw-r--r-- | tests/spi25.c | 59 | ||||
-rw-r--r-- | tests/tests.c | 1 | ||||
-rw-r--r-- | tests/tests.h | 1 |
22 files changed, 184 insertions, 3 deletions
@@ -134,6 +134,7 @@ int write_82802ab(struct flashctx *flash, const uint8_t *src, unsigned int start chip_writeb(flash, 0x40, dst); chip_writeb(flash, *src++, dst++); wait_82802ab(flash); + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len); } /* FIXME: Ignore errors for now. */ @@ -550,6 +550,7 @@ int spi_write_at45db(struct flashctx *flash, const uint8_t *buf, unsigned int st msg_cerr("Writing page %u failed!\n", i); return 1; } + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + page_size, len); } return 0; } diff --git a/cli_classic.c b/cli_classic.c index 83ac5383e..212534c94 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -79,6 +79,7 @@ static void cli_classic_usage(const char *name) #if CONFIG_PRINT_WIKI == 1 " -z | --list-supported-wiki print supported devices in wiki syntax\n" #endif + " --progress show progress percentage on the standard output\n" " -p | --programmer <name>[:<param>] specify the programmer device. One of\n"); list_programmers_linebreak(4, 80, 0); printf(".\n\nYou can specify one of -h, -R, -L, " @@ -472,6 +473,7 @@ int main(int argc, char *argv[]) uint32_t wp_start = 0, wp_len = 0; int read_it = 0, extract_it = 0, write_it = 0, erase_it = 0, verify_it = 0; int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0; + int show_progress = 0; struct flashrom_layout *layout = NULL; static const struct programmer_entry *prog = NULL; enum { @@ -487,6 +489,7 @@ int main(int argc, char *argv[]) OPTION_WP_ENABLE, OPTION_WP_DISABLE, OPTION_WP_LIST, + OPTION_PROGRESS, }; int ret = 0; @@ -523,6 +526,7 @@ int main(int argc, char *argv[]) {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'R'}, {"output", 1, NULL, 'o'}, + {"progress", 0, NULL, OPTION_PROGRESS}, {NULL, 0, NULL, 0}, }; @@ -763,6 +767,9 @@ int main(int argc, char *argv[]) cli_classic_abort_usage("No log filename specified.\n"); } break; + case OPTION_PROGRESS: + show_progress = 1; + break; default: cli_classic_abort_usage(NULL); break; @@ -934,6 +941,13 @@ int main(int argc, char *argv[]) fill_flash = &flashes[0]; + unsigned int progress_user_data[FLASHROM_PROGRESS_NR]; + struct flashrom_progress progress_state = { + .user_data = progress_user_data + }; + if (show_progress) + flashrom_set_progress_callback(fill_flash, &flashrom_progress_cb, &progress_state); + print_chip_support_status(fill_flash->chip); unsigned int limitexceeded = count_max_decode_exceedings(fill_flash); diff --git a/cli_output.c b/cli_output.c index 629db676d..e5b829a7d 100644 --- a/cli_output.c +++ b/cli_output.c @@ -64,6 +64,31 @@ void start_logging(void) verbose_screen = oldverbose_screen; } +static const char *flashrom_progress_stage_to_string(enum flashrom_progress_stage stage) +{ + if (stage == FLASHROM_PROGRESS_READ) + return "READ"; + if (stage == FLASHROM_PROGRESS_WRITE) + return "WRITE"; + if (stage == FLASHROM_PROGRESS_ERASE) + return "ERASE"; + return "UNKNOWN"; +} + +void flashrom_progress_cb(struct flashrom_flashctx *flashctx) +{ + struct flashrom_progress *progress_state = flashctx->progress_state; + unsigned int pc = 0; + unsigned int *percentages = progress_state->user_data; + if (progress_state->current > 0 && progress_state->total > 0) + pc = ((unsigned long long) progress_state->current * 10000llu) / + ((unsigned long long) progress_state->total * 100llu); + if (percentages[progress_state->stage] != pc) { + percentages[progress_state->stage] = pc; + msg_ginfo("[%s] %u%% complete... ", flashrom_progress_stage_to_string(progress_state->stage), pc); + } +} + /* Please note that level is the verbosity, not the importance of the message. */ int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap) { diff --git a/dediprog.c b/dediprog.c index 8a05a7c16..3bd61a08c 100644 --- a/dediprog.c +++ b/dediprog.c @@ -658,6 +658,7 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, u msg_perr("SPI bulk write failed, expected %i, got %s!\n", 512, libusb_error_name(ret)); return 1; } + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, count); } return 0; diff --git a/en29lv640b.c b/en29lv640b.c index 5b019047e..6c0a565a8 100644 --- a/en29lv640b.c +++ b/en29lv640b.c @@ -48,6 +48,7 @@ int write_en29lv640b(struct flashctx *flash, const uint8_t *src, unsigned int st #endif dst += 2; src += 2; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 2, len); } /* FIXME: Ignore errors for now. */ diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 58f5ec0cc..3dac4b9b7 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -53,7 +53,8 @@ flashrom \- detect, read, write, verify and erase flash chips [\fB\-\-wp\-status\fR] [\fB\-\-wp\-list\fR] [\fB\-\-wp\-enable\fR|\fB\-\-wp\-disable\fR] [\fB\-\-wp\-range\fR <start>,<length>|\fB\-\-wp\-region\fR <region>] [\fB\-n\fR] [\fB\-N\fR] [\fB\-f\fR])] - [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>] + [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>] [\fB\-\-progress\fR] + .SH DESCRIPTION .B flashrom is a utility for detecting, reading, writing, verifying and erasing flash @@ -445,6 +446,9 @@ If the file already exists, it will be overwritten. This is the recommended way to gather logs from flashrom because they will be verbose even if the on-screen messages are not verbose and don't require output redirection. .TP +.B "\-\-progress" +Show progress percentage of operations on the standard output. +.TP .B "\-R, \-\-version" Show version information and exit. .SH PROGRAMMER-SPECIFIC INFORMATION diff --git a/include/flash.h b/include/flash.h index 27ade09b6..45533ba9b 100644 --- a/include/flash.h +++ b/include/flash.h @@ -350,6 +350,9 @@ struct flashrom_flashctx { chip_restore_fn_cb_t func; uint8_t status; } chip_restore_fn[MAX_CHIP_RESTORE_FUNCTIONS]; + /* Progress reporting */ + flashrom_progress_callback *progress_callback; + struct flashrom_progress *progress_state; }; /* Timing used in probe routines. ZERO is -2 to differentiate between an unset @@ -446,6 +449,7 @@ int open_logfile(const char * const filename); int close_logfile(void); void start_logging(void); int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap); +void flashrom_progress_cb(struct flashrom_flashctx *flashctx); /* Let gcc and clang check for correct printf-style format strings. */ int print(enum flashrom_log_level level, const char *fmt, ...) #ifdef __MINGW32__ @@ -474,6 +478,7 @@ __attribute__((format(printf, 2, 3))); #define msg_gspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* general debug spew */ #define msg_pspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* programmer debug spew */ #define msg_cspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* chip debug spew */ +void update_progress(struct flashctx *flash, enum flashrom_progress_stage stage, size_t current, size_t total); /* spi.c */ struct spi_command { diff --git a/include/libflashrom.h b/include/libflashrom.h index cf1f46234..21a5785f3 100644 --- a/include/libflashrom.h +++ b/include/libflashrom.h @@ -69,6 +69,34 @@ typedef int(flashrom_log_callback)(enum flashrom_log_level, const char *format, */ void flashrom_set_log_callback(flashrom_log_callback *log_callback); +enum flashrom_progress_stage { + FLASHROM_PROGRESS_READ, + FLASHROM_PROGRESS_WRITE, + FLASHROM_PROGRESS_ERASE, + FLASHROM_PROGRESS_NR, +}; +struct flashrom_progress { + enum flashrom_progress_stage stage; + size_t current; + size_t total; + void *user_data; +}; +struct flashrom_flashctx; +typedef void(flashrom_progress_callback)(struct flashrom_flashctx *flashctx); +/** + * @brief Set the progress callback function. + * + * Set a callback function which will be invoked whenever libflashrom wants + * to indicate the progress has changed. This allows frontends to do whatever + * they see fit with such values, e.g. update a progress bar in a GUI tool. + * + * @param progress_callback Pointer to the new progress callback function. + * @param progress_state Pointer to progress state to include with the progress + * callback. + */ +void flashrom_set_progress_callback(struct flashrom_flashctx *const flashctx, + flashrom_progress_callback *progress_callback, struct flashrom_progress *progress_state); + /** @} */ /* end flashrom-general */ /** @@ -174,7 +202,6 @@ int flashrom_programmer_shutdown(struct flashrom_programmer *flashprog); * @{ */ -struct flashrom_flashctx; /** * @brief Probe for a flash chip. * @@ -291,6 +291,7 @@ static int it8716f_spi_chip_write_256(struct flashctx *flash, const uint8_t *buf int ret = it8716f_spi_page_program(flash, buf, start); if (ret) return ret; + update_progress(flash, FLASHROM_PROGRESS_WRITE, chip->page_size - len, chip->page_size); start += chip->page_size; len -= chip->page_size; buf += chip->page_size; @@ -421,6 +421,7 @@ int write_jedec_1(struct flashctx *flash, const uint8_t *src, unsigned int start if (write_byte_program_jedec_common(flash, src, dst, mask)) failed = 1; dst++, src++; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len); } if (failed) msg_cerr(" writing sector at 0x%" PRIxPTR " failed!\n", olddst); @@ -487,6 +488,7 @@ int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start, * we're OK for now. */ unsigned int page_size = flash->chip->page_size; + unsigned int nwrites = (start + len - 1) / page_size; /* Warning: This loop has a very unusual condition and body. * The loop needs to go through each page with at least one affected @@ -497,7 +499,7 @@ int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start, * (start + len - 1) / page_size. Since we want to include that last * page as well, the loop condition uses <=. */ - for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { + for (i = start / page_size; i <= nwrites; i++) { /* Byte position of the first byte in the range in this page. */ /* starthere is an offset to the base address of the chip. */ starthere = max(start, i * page_size); @@ -506,6 +508,7 @@ int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start, if (write_page_write_jedec_common(flash, buf + starthere - start, starthere, lenhere)) return 1; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, nwrites + 1); } return 0; diff --git a/libflashrom.c b/libflashrom.c index e70c1d1af..0c6613e94 100644 --- a/libflashrom.c +++ b/libflashrom.c @@ -65,6 +65,25 @@ int print(const enum flashrom_log_level level, const char *const fmt, ...) return 0; } +void flashrom_set_progress_callback(struct flashrom_flashctx *flashctx, flashrom_progress_callback *progress_callback, struct flashrom_progress *progress_state) +{ + flashctx->progress_callback = progress_callback; + flashctx->progress_state = progress_state; +} +/** @private */ +void update_progress(struct flashrom_flashctx *flashctx, enum flashrom_progress_stage stage, size_t current, size_t total) +{ + if (flashctx->progress_callback == NULL) + return; + if (current > total) + current = total; + + flashctx->progress_state->stage = stage; + flashctx->progress_state->current = current; + flashctx->progress_state->total = total; + flashctx->progress_callback(flashctx); +} + const char *flashrom_version_info(void) { return flashrom_version; diff --git a/libflashrom.map b/libflashrom.map index 2249d3549..b3af70b11 100644 --- a/libflashrom.map +++ b/libflashrom.map @@ -24,6 +24,7 @@ LIBFLASHROM_1.0 { flashrom_programmer_init; flashrom_programmer_shutdown; flashrom_set_log_callback; + flashrom_set_progress_callback; flashrom_shutdown; flashrom_version_info; local: *; diff --git a/linux_mtd.c b/linux_mtd.c index 445a90359..88488c0b2 100644 --- a/linux_mtd.c +++ b/linux_mtd.c @@ -214,6 +214,7 @@ static int linux_mtd_read(struct flashctx *flash, uint8_t *buf, } i += step; + update_progress(flash, FLASHROM_PROGRESS_READ, i, len); } return 0; @@ -256,6 +257,7 @@ static int linux_mtd_write(struct flashctx *flash, const uint8_t *buf, } i += step; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i, len); } return 0; @@ -292,6 +294,7 @@ static int linux_mtd_erase(struct flashctx *flash, __func__, ret, strerror(errno)); return 1; } + update_progress(flash, FLASHROM_PROGRESS_ERASE, u + data->erasesize, len); } return 0; diff --git a/lspcon_i2c_spi.c b/lspcon_i2c_spi.c index cabe21f6c..f3c11d665 100644 --- a/lspcon_i2c_spi.c +++ b/lspcon_i2c_spi.c @@ -354,6 +354,7 @@ static int lspcon_i2c_spi_read(struct flashctx *flash, uint8_t *buf, for (i = 0; i < len; i += LSPCON_PAGE_SIZE) { ret |= lspcon_i2c_spi_map_page(fd, start + i); ret |= lspcon_i2c_spi_read_data(fd, PAGE_ADDRESS, buf + i, min(len - i, LSPCON_PAGE_SIZE)); + update_progress(flash, FLASHROM_PROGRESS_READ, i + LSPCON_PAGE_SIZE, len); } return ret; @@ -394,6 +395,7 @@ static int lspcon_i2c_spi_write_256(struct flashctx *flash, const uint8_t *buf, for (unsigned int i = 0; i < len; i += LSPCON_PAGE_SIZE) { ret |= lspcon_i2c_spi_map_page(fd, start + i); ret |= lspcon_i2c_spi_write_page(fd, buf + i, min(len - i, LSPCON_PAGE_SIZE)); + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + LSPCON_PAGE_SIZE, len); } ret |= lspcon_i2c_spi_enable_write_protection(fd); diff --git a/realtek_mst_i2c_spi.c b/realtek_mst_i2c_spi.c index 954150df5..c7de2fe7d 100644 --- a/realtek_mst_i2c_spi.c +++ b/realtek_mst_i2c_spi.c @@ -398,6 +398,7 @@ static int realtek_mst_i2c_spi_write_256(struct flashctx *flash, const uint8_t * ret |= realtek_mst_i2c_execute_write(fd); if (ret) break; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + RTK_PAGE_SIZE, len); } return ret; @@ -101,6 +101,8 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, { int ret; size_t to_read; + size_t start_address = start; + size_t end_address = len - start; for (; len; len -= to_read, buf += to_read, start += to_read) { /* Do not cross 16MiB boundaries in a single transfer. This helps with @@ -110,6 +112,7 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, ret = flash->mst->spi.read(flash, buf, start, to_read); if (ret) return ret; + update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address); } return 0; } @@ -674,11 +674,14 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, { int ret; size_t to_read; + size_t start_address = start; + size_t end_address = len - start; for (; len; len -= to_read, buf += to_read, start += to_read) { to_read = min(chunksize, len); ret = spi_nbyte_read(flash, start, buf, to_read); if (ret) return ret; + update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address); } return 0; } @@ -698,6 +701,8 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s * we're OK for now. */ unsigned int page_size = flash->chip->page_size; + size_t start_address = start; + size_t end_address = len - start; /* Warning: This loop has a very unusual condition and body. * The loop needs to go through each page with at least one affected @@ -722,6 +727,7 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s if (rc) return rc; } + update_progress(flash, FLASHROM_PROGRESS_WRITE, start - start_address + lenhere, end_address); } return 0; @@ -741,6 +747,7 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st for (i = start; i < start + len; i++) { if (spi_nbyte_program(flash, i, buf + i - start, 1)) return 1; + update_progress(flash, FLASHROM_PROGRESS_WRITE, i - start, len - start); } return 0; } diff --git a/sst28sf040.c b/sst28sf040.c index 3da25f127..9a08d6b61 100644 --- a/sst28sf040.c +++ b/sst28sf040.c @@ -92,6 +92,7 @@ int write_28sf040(struct flashctx *flash, const uint8_t *src, unsigned int start /* wait for Toggle bit ready */ toggle_ready_jedec(flash, bios); + update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len); } return 0; diff --git a/tests/spi25.c b/tests/spi25.c index f57251ea8..f10191040 100644 --- a/tests/spi25.c +++ b/tests/spi25.c @@ -67,6 +67,65 @@ int __wrap_spi_send_command(const struct flashctx *flash, return 0; } +static void spi_read_progress_cb(struct flashrom_flashctx *flashctx) +{ + struct flashrom_progress *progress_state = flashctx->progress_state; + uint32_t *cnt = (uint32_t *) progress_state->user_data; + assert_int_equal(0x300, progress_state->total); + switch (*cnt) { + case 0: + assert_int_equal(0x100, progress_state->current); + break; + case 1: + assert_int_equal(0x200, progress_state->current); + break; + case 2: + assert_int_equal(0x300, progress_state->current); + break; + case 3: + assert_int_equal(0x300, progress_state->current); + break; + case 4: + assert_int_equal(0x300, progress_state->current); + break; + default: + fail(); + } + (*cnt)++; +} + +void spi_read_chunked_test_success(void **state) +{ + (void) state; /* unused */ + uint8_t buf[0x400] = { 0x0 }; + uint32_t cnt = 0; + const unsigned int max_data_read = 0x100; + const unsigned int offset = 0x100; + struct registered_master mst = { + .spi.read = default_spi_read, + .spi.max_data_read = max_data_read + }; + + /* setup initial test state */ + struct flashctx flashctx = { + .chip = &mock_chip, + .mst = &mst + }; + struct flashrom_progress progress_state = { + .user_data = (void *) &cnt, + }; + flashrom_set_progress_callback(&flashctx, spi_read_progress_cb, &progress_state); + for (int i = 0; i < 4; i++) { + expect_memory(__wrap_spi_send_command, flash, + &flashctx, sizeof(flashctx)); + will_return(__wrap_spi_send_command, JEDEC_WRDI); + will_return(__wrap_spi_send_command, JEDEC_READ); + will_return(__wrap_spi_send_command, max_data_read); + } + assert_int_equal(0, spi_chip_read(&flashctx, buf, offset, sizeof(buf))); + assert_int_equal(5, cnt); +} + void spi_write_enable_test_success(void **state) { (void) state; /* unused */ diff --git a/tests/tests.c b/tests/tests.c index 2f955ff40..a719a8fd0 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -391,6 +391,7 @@ int main(void) const struct CMUnitTest spi25_tests[] = { cmocka_unit_test(spi_write_enable_test_success), cmocka_unit_test(spi_write_disable_test_success), + cmocka_unit_test(spi_read_chunked_test_success), cmocka_unit_test(probe_spi_rdid_test_success), cmocka_unit_test(probe_spi_rdid4_test_success), cmocka_unit_test(probe_spi_rems_test_success), diff --git a/tests/tests.h b/tests/tests.h index e2b221130..5ffc14565 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -31,6 +31,7 @@ void flashbuses_to_text_test_success(void **state); /* spi25.c */ void spi_write_enable_test_success(void **state); void spi_write_disable_test_success(void **state); +void spi_read_chunked_test_success(void **state); void probe_spi_rdid_test_success(void **state); void probe_spi_rdid4_test_success(void **state); void probe_spi_rems_test_success(void **state); |