From 123441e17fc5a9a40e45fde5ecc8209e5c0ad0cc Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Mon, 24 Aug 2015 13:31:17 +1000 Subject: external/gard: Check the validity of the flash If the GUARD partition has been corrupted such that ECC checks fail and not even the first gard record can be read then the gard tool will be unable to do anything. If this happens it is possible that hostboot will have a similar problem. The only sane thing to do at is point is probably to wipe the GUARD partition. This patch adds a check for this case and provides the user with the option to wipe the entirety of the GUARD partition to attempt recovery. Signed-off-by: Cyril Bur Signed-off-by: Stewart Smith --- external/gard/gard.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) (limited to 'external/gard') diff --git a/external/gard/gard.c b/external/gard/gard.c index d84e098..7b0ea2b 100644 --- a/external/gard/gard.c +++ b/external/gard/gard.c @@ -566,6 +566,56 @@ static int do_clear(struct gard_ctx *ctx, int argc, char **argv) return rc; } +int check_gard_partition(struct gard_ctx *ctx) +{ + int rc; + struct gard_record gard; + char msg[2]; + + if (ctx->gard_data_len == 0 || ctx->gard_data_len % sizeof(struct gard_record) != 0) + /* Just warn for now */ + fprintf(stderr, "The %s partition doesn't appear to be an exact multiple of" + "gard records in size: %lu vs %u (or partition is zero in length)\n", + FLASH_GARD_PART, sizeof(struct gard_record), ctx->gard_data_len); + + /* + * Attempt to read the first record, nothing can really operate if the + * first record is dead. There (currently) isn't a way to validate more + * than ECC correctness. + */ + rc = blocklevel_read(ctx->bl, ctx->gard_data_pos, &gard, sizeof(gard)); + if (rc == FLASH_ERR_ECC_INVALID) { + fprintf(stderr, "The data at the GUARD partition does not appear to be valid gard data\n"); + fprintf(stderr, "Clear the entire GUARD partition? [y/N]\n"); + if (fgets(msg, sizeof(msg), stdin) == NULL) { + fprintf(stderr, "Couldn't read from standard input\n"); + return -1; + } + if (msg[0] == 'y') { + rc = blocklevel_erase(ctx->bl, ctx->gard_data_pos, ctx->gard_data_len); + if (rc) { + fprintf(stderr, "Couldn't erase flash partition. Bailing out\n"); + return rc; + } + + memset(&gard, INT_MAX, sizeof(gard)); + + rc = blocklevel_smart_write(ctx->bl, ctx->gard_data_pos, &gard, sizeof(gard)); + if (rc) { + fprintf(stderr, "Couldn't create a sane first gard record. Bailing out\n"); + return rc; + } + } + /* + * else leave rc as is so that the main bails out, not going to be + * able to do sensible anyway + */ + } + return rc; +} + + + __attribute__ ((unused)) static int do_nop(struct gard_ctx *ctx, int argc, char **argv) { @@ -718,11 +768,11 @@ int main(int argc, char **argv) ctx->gard_data_len = ctx->f_size; } - if (ctx->gard_data_len == 0 || ctx->gard_data_len % sizeof(struct gard_record) != 0) - /* Just warn for now */ - fprintf(stderr, "The %s partition doesn't appear to be an exact multiple of" - "gard records in size: %lu vs %u (or partition is zero in length)\n", - FLASH_GARD_PART, sizeof(struct gard_record), ctx->gard_data_len); + rc = check_gard_partition(ctx); + if (rc) { + fprintf(stderr, "Does not appear to be sane gard data\n"); + goto out; + } for (i = 0; i < ARRAY_SIZE(actions); i++) { if (!strcmp(actions[i].name, action)) { -- cgit v1.1