From: Hector Palacios Date: Wed, 16 Oct 2013 10:30:14 +0200 Subject: added option to verify data written to flash This patch adds a -c (check) option to the update command. This option will read back the data written to the flash and compare to the original contents in RAM, to verify the write operation was successful. Signed-off-by: Hector Palacios Reviewed-by: Robert Hodaszi --- src/main.c | 22 ++++++-- src/mtd.c | 138 +++++++++++++++++++++++++++++++++++++++---------- src/mtd.h | 10 ++-- src/plat_boot_config.h | 2 +- 4 files changed, 136 insertions(+), 36 deletions(-) diff --git a/src/main.c b/src/main.c index 70517b0..8774045 100644 --- a/src/main.c +++ b/src/main.c @@ -82,10 +82,12 @@ void usage(void) " -x .................................... Add 1k-padding in the head\n" " -n .................................... Dry run (don't commit to flash)\n" " -w .................................... Commit to flash\n" + " -c .................................... Check committed data in flash\n" "\n" " update [-v] [KEY] [KOBS] [-0|1] .. Update a single bootstream\n" " -v .................................... Verbose mode\n" " -0|1 .................................. Update specified bootstream #\n" + " -c .................................... Check committed data in flash\n" "\n" " extract [-v] [KEY] [KOBS] [-0|1] . Extract a bootstream from flash\n" " -v .................................... Verbose mode\n" @@ -390,7 +392,8 @@ int extract_main(int argc, char **argv) return 0; } -static int perform_bootstream_update(struct mtd_data *md, FILE *infp, int image_mask) +static int perform_bootstream_update(struct mtd_data *md, FILE *infp, + int image_mask, int check) { int i, r; unsigned int size, start, avail, end, update; @@ -435,7 +438,8 @@ static int perform_bootstream_update(struct mtd_data *md, FILE *infp, int image_ update |= UPDATE_BS(i); } - r = plat_config_data->rom_mtd_commit_structures(md, infp, UPDATE_LDLB | update); + r = plat_config_data->rom_mtd_commit_structures(md, infp, + UPDATE_LDLB | update, check); if (r < 0) { fprintf(stderr, "FAILED to commit structures\n"); return -1; @@ -457,6 +461,7 @@ int update_main(int argc, char **argv) char ascii[20 * 2 + 1]; int device_key; uint8_t *keyp; + int check; memset(key, 0, sizeof(key)); device_key = 0; @@ -473,6 +478,7 @@ int update_main(int argc, char **argv) image_mask = 0; /* no image */ flags = 0; j = 0; + check = 0; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { @@ -500,6 +506,9 @@ int update_main(int argc, char **argv) exit(5); } break; + case 'c': + check = 1; + break; case 'v': flags |= F_VERBOSE; break; @@ -545,7 +554,7 @@ int update_main(int argc, char **argv) if (flags & F_VERBOSE) mtd_dump(md); - r = perform_bootstream_update(md, infp, image_mask); + r = perform_bootstream_update(md, infp, image_mask, check); if (r != 0) { fprintf(stderr, "Unable to perform bootstream update\n"); usage(); @@ -597,6 +606,7 @@ int init_main(int argc, char **argv) FILE *infp; loff_t ofs; int dryrun; + int check; int padding = 0; struct mtd_config cfg; uint8_t key[16]; @@ -619,6 +629,7 @@ int init_main(int argc, char **argv) image = 0; /* first image */ flags = 0; dryrun = 0; + check = 0; j = 0; for (i = 1; i < argc; i++) { @@ -640,6 +651,9 @@ int init_main(int argc, char **argv) case 'w': dryrun = 0; break; + case 'c': + check = 1; + break; case 'n': dryrun = 1; break; @@ -738,7 +752,7 @@ int init_main(int argc, char **argv) mtd_dump_structure(md); if (!dryrun) { - r = plat_config_data->rom_mtd_commit_structures(md, infp, UPDATE_ALL); + r = plat_config_data->rom_mtd_commit_structures(md, infp, UPDATE_ALL, check); if (r < 0) { fprintf(stderr, "FAILED to commit structures\n"); exit(5); diff --git a/src/mtd.c b/src/mtd.c index 9ea92ad..77ba307 100644 --- a/src/mtd.c +++ b/src/mtd.c @@ -2344,7 +2344,7 @@ int v4_rom_mtd_init(struct mtd_data *md, FILE *fp) int mtd_commit_bcb(struct mtd_data *md, char *bcb_name, loff_t ofs1, loff_t ofs2, loff_t ofs_mchip, - loff_t end, size_t size, int ecc) + loff_t end, size_t size, int ecc, int verify) { int chip; loff_t end_index, search_area_indices[2], o; @@ -2355,6 +2355,13 @@ int mtd_commit_bcb(struct mtd_data *md, char *bcb_name, unsigned search_area_size_in_strides; unsigned search_area_size_in_bytes; unsigned count; + char *readbuf = NULL; + + if (verify) { + readbuf = malloc(mtd_writesize(md)); + if (NULL == readbuf) + return -1; + } vp(md, "-------------- Start to write the [ %s ] -----\n", bcb_name); //---------------------------------------------------------------------- @@ -2457,6 +2464,20 @@ int mtd_commit_bcb(struct mtd_data *md, char *bcb_name, err ++; } + if (verify) { + //------------------------------------------------------ + // Verify the written data + //------------------------------------------------------ + r = pread(md->part[chip].fd, readbuf, mtd_writesize(md), o); + if (r != mtd_writesize(md)) { + fprintf(stderr, "mtd: Failed to read @0x%llx (%d)\n", o, r); + goto err_free; + } + if (memcmp(md->buf, readbuf, mtd_writesize(md))) { + fprintf(stderr, "mtd: Verification error @0x%llx\n", o); + goto err_free; + } + } } } @@ -2466,16 +2487,31 @@ int mtd_commit_bcb(struct mtd_data *md, char *bcb_name, if (md->flags & F_VERBOSE) printf("%s(%s): status %d\n\n", __func__, bcb_name, err); - return err; +err_free: + if (verify) + free(readbuf); + if (err) { + fprintf(stderr, "mtd: %d errors\n", err); + return -1; + } + else + return 0; } -int write_boot_stream(struct mtd_data *md, FILE *fp) +int write_boot_stream(struct mtd_data *md, FILE *fp, int verify) { int startpage, start, size; loff_t ofs, end; - int i, r, chunk; + int i, r = 0, chunk; int chip = 0; struct fcb_block *fcb = &md->fcb.FCB_Block; + char *readbuf = NULL; + + if (verify) { + readbuf = malloc(mtd_writesize(md)); + if (NULL == readbuf) + return -1; + } vp(md, "---------- Start to write the [ %s ]----\n", (char*)md->private); for (i = 0; i < 2; i++) { @@ -2530,7 +2566,7 @@ int write_boot_stream(struct mtd_data *md, FILE *fp) r = fread(md->buf, 1, chunk, fp); if (r < 0) { fprintf(stderr, "mtd: Failed %d (fread %d)\n", r, chunk); - return -1; + goto err_free; } if (r < chunk) { memset(md->buf + r, 0, chunk - r); @@ -2539,10 +2575,30 @@ int write_boot_stream(struct mtd_data *md, FILE *fp) /* write page */ r = mtd_write_page(md, chip, ofs, 1); - if (r != mtd_writesize(md)) + if (r != mtd_writesize(md)) { fprintf(stderr, "mtd: Failed to write BS @0x%llx (%d)\n", ofs, r); + r = -1; + goto err_free; + } + if (verify) { + //------------------------------------------------------ + // Verify the written data + //------------------------------------------------------ + r = pread(md->part[chip].fd, readbuf, + mtd_writesize(md), ofs); + if (r != mtd_writesize(md)) { + fprintf(stderr, "mtd: Failed to read BS @0x%llx (%d)\n", ofs, r); + r = -1; + goto err_free; + } + if (memcmp(md->buf, readbuf, mtd_writesize(md))) { + fprintf(stderr, "mtd: Verification error @0x%llx\n", ofs); + r = -1; + goto err_free; + } + } ofs += mtd_writesize(md); size -= chunk; } @@ -2555,19 +2611,26 @@ int write_boot_stream(struct mtd_data *md, FILE *fp) */ memset(md->buf, 0, mtd_writesize(md)); r = mtd_write_page(md, chip, ofs, 1); - if (r != mtd_writesize(md)) + if (r != mtd_writesize(md)) { fprintf(stderr, "Failed to write safe page\n"); + r = -1; + goto err_free; + } vp(md, "mtd: We write one page for save guard. *\n"); - if (ofs >= end) { fprintf(stderr, "mtd: Failed to write BS#%d\n", i); - return -1; + r = -1; + goto err_free; } } - return 0; + +err_free: + if (verify) + free(readbuf); + return r; } -int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) +int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify) { int startpage, start, size; unsigned int search_area_sz, stride; @@ -2666,7 +2729,9 @@ int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) if (r < 0) return r; - mtd_commit_bcb(md, "NCB", 0, 1, 0, 1, size, false); + r = mtd_commit_bcb(md, "NCB", 0, 1, 0, 1, size, false, verify); + if (r < 0) + return r; } if (flags & UPDATE_LDLB) { @@ -2675,7 +2740,10 @@ int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, md->curr_ldlb, sizeof(*md->curr_ldlb)); - mtd_commit_bcb(md, "LDLB", 2, 3, 1, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "LDLB", 2, 3, 1, 1, mtd_writesize(md), true, + verify); + if (r < 0) + return r; } if (flags & UPDATE_DBBT) { @@ -2684,7 +2752,11 @@ int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, md->curr_dbbt, sizeof(*md->curr_dbbt)); - mtd_commit_bcb(md, "DBBT", 4, 5, 2, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "DBBT", 4, 5, 2, 1, mtd_writesize(md), true, + verify); + if (r < 0) + return r; + for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) { if (md->flags & F_MULTICHIP) { @@ -2766,7 +2838,7 @@ static void write_dbbt(struct mtd_data *md, int dbbt_num) } } -int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) +int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify) { int size ,r; @@ -2779,8 +2851,11 @@ int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) size = mtd_writesize(md) + mtd_oobsize(md); r = fcb_encrypt(&md->fcb, md->buf, size, 1); if (r < 0) - return r; - mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, size, false); + return -1; + + r = mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, size, false, verify); + if (r < 0) + return -1; //---------------------------------------------------------------------- // Write the DBBT search area. @@ -2788,14 +2863,17 @@ int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, &(md->dbbt28), sizeof(md->dbbt28)); dbbt_checksum(md, &md->dbbt28); - mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true, + verify); + if (r < 0) + return -1; write_dbbt(md, 1); /* only write the DBBT for nand0 */ /* write the boot image. */ - return write_boot_stream(md, fp); + return write_boot_stream(md, fp, verify); } -int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) +int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify) { int startpage, start, size; unsigned int search_area_size_in_bytes, stride_size_in_bytes; @@ -2832,7 +2910,9 @@ int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, &(md->fcb), sizeof(md->fcb)); - mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, mtd_writesize(md), true, verify); + if (r < 0) + return -1; //---------------------------------------------------------------------- // Write the DBBT search area. @@ -2841,7 +2921,9 @@ int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, &(md->dbbt28), sizeof(md->dbbt28)); - mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true, verify); + if (r < 0) + return -1; //---------------------------------------------------------------------- // Write the DBBT table area. @@ -2985,7 +3067,7 @@ int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) return 0; } -int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) +int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify) { int size, i, r, chip = 0; loff_t ofs; @@ -2997,12 +3079,16 @@ int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) r = fcb_encrypt(&md->fcb, md->buf, size, 1); if (r < 0) return r; - mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, size, false); + r = mtd_commit_bcb(md, "FCB", 0, 0, 0, 1, size, false, verify); + if (r < 0) + return r; /* [2] Write the DBBT search area. */ memset(md->buf, 0, mtd_writesize(md)); memcpy(md->buf, &(md->dbbt50), sizeof(md->dbbt50)); - mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true); + r = mtd_commit_bcb(md, "DBBT", 1, 1, 1, 1, mtd_writesize(md), true, verify); + if (r < 0) + return -1; /* Write the DBBT table area. */ memset(md->buf, 0, mtd_writesize(md)); @@ -3023,7 +3109,7 @@ int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags) } /* [3] Write the two boot streams. */ - return write_boot_stream(md, fp); + return write_boot_stream(md, fp, verify); } #undef ARG diff --git a/src/mtd.h b/src/mtd.h index 18e4d70..699e505 100644 --- a/src/mtd.h +++ b/src/mtd.h @@ -295,11 +295,11 @@ int mtd_markbad(struct mtd_data *md, int chip, loff_t ofs); #define UPDATE_BS(x) (0x08 << ((x) & 1)) #define UPDATE_ALL (UPDATE_NCB | UPDATE_LDLB | UPDATE_DBBT | UPDATE_BS0 | UPDATE_BS1) -int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags); -int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags); -int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags); -int v3_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags); -int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags); +int v0_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify); +int v1_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify); +int v2_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify); +int v3_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify); +int v4_rom_mtd_commit_structures(struct mtd_data *md, FILE *fp, int flags, int verify); int mtd_set_ecc_mode(struct mtd_data *md, int ecc); diff --git a/src/plat_boot_config.h b/src/plat_boot_config.h index 8242ede..a3c03a7 100644 --- a/src/plat_boot_config.h +++ b/src/plat_boot_config.h @@ -55,7 +55,7 @@ typedef struct _platform_config_t { uint32_t m_u32Arm_type; uint32_t m_u32DBBT_FingerPrint; int (* rom_mtd_init)(struct mtd_data *md, FILE *fp); - int (* rom_mtd_commit_structures)(struct mtd_data *md, FILE *fp, int flags); + int (* rom_mtd_commit_structures)(struct mtd_data *md, FILE *fp, int flags, int verify); } platform_config; extern platform_config *plat_config_data;