From dd25f4cb2eb606d9f364d955f8c1a9a4cecac7ec Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 19 Oct 2024 11:23:49 +0300 Subject: [PATCH 1/3] target_flash: Implement blank check * Reuse flash write buffer for block reads * Compare against erased value and skip to next sector on mismatch * Indicate progress via tc_printf() to gdb_if.c or BMDA stdout --- src/include/target.h | 1 + src/target/target.c | 12 ++++++++ src/target/target_flash.c | 58 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/include/target.h b/src/include/target.h index 182c745ce35..f742427112f 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -71,6 +71,7 @@ bool target_flash_erase(target_s *target, target_addr_t addr, size_t len); bool target_flash_write(target_s *target, target_addr_t dest, const void *src, size_t len); bool target_flash_complete(target_s *target); bool target_flash_mass_erase(target_s *target); +bool target_flash_blank_check(target_s *target); /* Register access functions */ size_t target_regs_size(target_s *target); diff --git a/src/target/target.c b/src/target/target.c index 3e4b2f3693e..56eeaa6cabb 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -45,11 +45,13 @@ target_s *target_list = NULL; static bool target_cmd_mass_erase(target_s *target, int argc, const char **argv); static bool target_cmd_range_erase(target_s *target, int argc, const char **argv); +static bool target_cmd_blank_check(target_s *target, int argc, const char **argv); static bool target_cmd_redirect_output(target_s *target, int argc, const char **argv); const command_s target_cmd_list[] = { {"erase_mass", target_cmd_mass_erase, "Erase whole device Flash"}, {"erase_range", target_cmd_range_erase, "Erase a range of memory on a device"}, + {"blank_check", target_cmd_blank_check, "Blank-check device Flash"}, {"redirect_stdout", target_cmd_redirect_output, "Redirect semihosting output to aux USB serial"}, {NULL, NULL, NULL}, }; @@ -553,6 +555,16 @@ static bool target_cmd_range_erase(target_s *const target, const int argc, const return target_flash_erase(target, addr, length); } +static bool target_cmd_blank_check(target_s *const target, const int argc, const char **const argv) +{ + (void)argc; + (void)argv; + gdb_out("Blank-checking device Flash: "); + const bool result = target_flash_blank_check(target); + gdb_out("done\n"); + return result; +} + static bool target_cmd_redirect_output(target_s *target, int argc, const char **argv) { if (argc == 1) { diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 0cd19e6cb70..ccafb79bb16 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -383,3 +383,61 @@ bool target_flash_complete(target_s *target) target_exit_flash_mode(target); return result; } + +static bool flash_blank_check(target_flash_s *flash, target_addr_t src, size_t len, target_addr_t *mismatch) +{ + bool result = true; /* Catch false returns with &= */ + target_s *target = flash->t; + platform_timeout_s timeout; + platform_timeout_set(&timeout, 500); + + while (len) { + const size_t offset = src % flash->writebufsize; + const size_t local_len = MIN(flash->writebufsize - offset, len); + /* Fetch chunk into sector buffer */ + target_mem32_read(target, flash->buf, src, local_len); + + /* Compare bytewise with erased value */ + const uint8_t erased = flash->erased; + for (size_t i = 0; i < local_len; i++) { + if (flash->buf[i] != erased) { + *mismatch = src + i; + return false; + } + } + src += local_len; + len -= local_len; + target_print_progress(&timeout); + } + return result; +} + +bool target_flash_blank_check(target_s *target) +{ + if (!target->flash) + return false; + + bool result = true; + target_addr_t mismatch = 0; + + for (target_flash_s *flash = target->flash; flash; flash = flash->next) { + if (!flash->buf && !flash_buffer_alloc(flash)) + return false; + + const target_addr_t local_end = flash->start + flash->length; + for (target_addr_t local_start = flash->start; local_start < local_end; local_start += flash->blocksize) { + result = flash_blank_check(flash, local_start, flash->blocksize, &mismatch); + if (!result) + tc_printf(target, "Has data at 0x%08" PRIx32 "\n", mismatch); + else + tc_printf(target, "Blank 0x%08" PRIx32 "+%" PRIu32 "\n", local_start, (uint32_t)flash->blocksize); + } + /* Free the operation buffer */ + if (flash->buf) { + free(flash->buf); + flash->buf = NULL; + } + } + + return result; +} From d5e87805524faa5f02d8fc2a3d51c1fffebc7831 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:29:06 +0300 Subject: [PATCH 2/3] target_flash: Simplify inner loop of blank_check --- src/target/target_flash.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index ccafb79bb16..5c5b07699fe 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -391,22 +391,18 @@ static bool flash_blank_check(target_flash_s *flash, target_addr_t src, size_t l platform_timeout_s timeout; platform_timeout_set(&timeout, 500); - while (len) { - const size_t offset = src % flash->writebufsize; - const size_t local_len = MIN(flash->writebufsize - offset, len); + for (size_t offset = 0U; offset < len; offset += flash->writebufsize) { /* Fetch chunk into sector buffer */ - target_mem32_read(target, flash->buf, src, local_len); + target_mem32_read(target, flash->buf, src + offset, flash->writebufsize); /* Compare bytewise with erased value */ const uint8_t erased = flash->erased; - for (size_t i = 0; i < local_len; i++) { + for (size_t i = 0; i < flash->writebufsize; i++) { if (flash->buf[i] != erased) { *mismatch = src + i; return false; } } - src += local_len; - len -= local_len; target_print_progress(&timeout); } return result; From 69f672e11de84a7a409585d7cfbb532d168343f2 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 18 Jan 2025 14:56:28 +0300 Subject: [PATCH 3/3] target_flash: Fix blank_check for pages smaller than writebufsize --- src/target/target_flash.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/target/target_flash.c b/src/target/target_flash.c index 5c5b07699fe..fe7374b753a 100644 --- a/src/target/target_flash.c +++ b/src/target/target_flash.c @@ -391,13 +391,16 @@ static bool flash_blank_check(target_flash_s *flash, target_addr_t src, size_t l platform_timeout_s timeout; platform_timeout_set(&timeout, 500); - for (size_t offset = 0U; offset < len; offset += flash->writebufsize) { + /* Pick smaller of: len = option bytes (8), writebufsize (1024), len = flash page (8192) */ + const size_t chunksize = flash->writebufsize < len ? flash->writebufsize : len; + + for (size_t offset = 0U; offset < len; offset += chunksize) { /* Fetch chunk into sector buffer */ - target_mem32_read(target, flash->buf, src + offset, flash->writebufsize); + target_mem32_read(target, flash->buf, src + offset, chunksize); /* Compare bytewise with erased value */ const uint8_t erased = flash->erased; - for (size_t i = 0; i < flash->writebufsize; i++) { + for (size_t i = 0; i < chunksize; i++) { if (flash->buf[i] != erased) { *mismatch = src + i; return false;