Skip to content

Commit

Permalink
target_flash: Implement blank check
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ALTracer committed Nov 21, 2024
1 parent 9ac66f5 commit d97fd6f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/include/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions src/target/target.c
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -516,6 +518,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) {
Expand Down
58 changes: 58 additions & 0 deletions src/target/target_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,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;
}

0 comments on commit d97fd6f

Please sign in to comment.