aboutsummaryrefslogtreecommitdiff
path: root/external/gard
diff options
context:
space:
mode:
authorCyril Bur <cyril.bur@au1.ibm.com>2015-08-24 13:31:17 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-08-28 15:14:12 +1000
commit123441e17fc5a9a40e45fde5ecc8209e5c0ad0cc (patch)
tree669363da7859ab80a62788129a3fa9c5ef3c062c /external/gard
parent1b30e6879819256497d24b46934558166fee5682 (diff)
downloadskiboot-123441e17fc5a9a40e45fde5ecc8209e5c0ad0cc.zip
skiboot-123441e17fc5a9a40e45fde5ecc8209e5c0ad0cc.tar.gz
skiboot-123441e17fc5a9a40e45fde5ecc8209e5c0ad0cc.tar.bz2
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 <cyril.bur@au1.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'external/gard')
-rw-r--r--external/gard/gard.c60
1 files changed, 55 insertions, 5 deletions
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)) {