aboutsummaryrefslogtreecommitdiff
path: root/external
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.ibm.com>2018-12-11 15:18:30 +1100
committerStewart Smith <stewart@linux.ibm.com>2019-02-14 17:03:54 +1100
commit816a1d7bb2efcaf2a4b62018b21984131cd52dd3 (patch)
tree7598b868a68e51ad2b387a60b76859662d4dfaa3 /external
parent3170270be92ad945600d25ced9352c39fc7f156a (diff)
downloadskiboot-816a1d7bb2efcaf2a4b62018b21984131cd52dd3.zip
skiboot-816a1d7bb2efcaf2a4b62018b21984131cd52dd3.tar.gz
skiboot-816a1d7bb2efcaf2a4b62018b21984131cd52dd3.tar.bz2
pflash: Support encoding/decoding ECC'd partitions
With the new --ecc option, pflash can add/remove ECC when reading/writing flash partitions protected by ECC. This is *not* flawless with current PNORs out in the wild though, as they do not typically fill the whole partition with valid ECC data, so you have to know how big the valid ECC'd data is and specify the size manually. Note that for some partitions this is pratically impossible without knowing the details of the content of the partition. A future patch is likely to introduce an option to "stop reading data when ECC starts failing and assume everything is okay rather than error out" to support reading the "valid" data from existing PNOR images. Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'external')
-rw-r--r--external/pflash/pflash.c43
-rw-r--r--external/pflash/test/results/00-usage.out4
-rw-r--r--external/pflash/test/results/05-bad-numbers.out4
3 files changed, 41 insertions, 10 deletions
diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
index c81520c..dfdfeb0 100644
--- a/external/pflash/pflash.c
+++ b/external/pflash/pflash.c
@@ -36,6 +36,7 @@
#include <libflash/libflash.h>
#include <libflash/libffs.h>
#include <libflash/blocklevel.h>
+#include <libflash/ecc.h>
#include <common/arch_flash.h>
#include "progress.h"
@@ -48,6 +49,7 @@ struct flash_details {
uint64_t toc;
uint64_t total_size;
uint32_t erase_granule;
+ bool mark_ecc;
};
/* Full pflash version number (possibly includes gitid). */
@@ -142,7 +144,7 @@ static struct ffs_handle *open_ffs(struct flash_details *flash)
int rc;
rc = ffs_init(flash->toc, flash->total_size,
- flash->bl, &ffsh, 0);
+ flash->bl, &ffsh, flash->mark_ecc);
if (rc) {
fprintf(stderr, "Error %d opening ffs !\n", rc);
if (flash->toc) {
@@ -429,7 +431,7 @@ static int program_file(struct blocklevel_device *bl,
}
printf("Programming & Verifying...\n");
- progress_init(size >> 8);
+ progress_init(size);
while(size) {
ssize_t len;
@@ -456,7 +458,7 @@ static int program_file(struct blocklevel_device *bl,
goto out;
}
start += len;
- progress_tick(actual_size >> 8);
+ progress_tick(actual_size);
}
progress_end();
@@ -487,7 +489,7 @@ static int do_read_file(struct blocklevel_device *bl, const char *file,
printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
file, start, start + size);
- progress_init(size >> 8);
+ progress_init(size);
while(size) {
ssize_t len;
@@ -511,7 +513,7 @@ static int do_read_file(struct blocklevel_device *bl, const char *file,
start += rc;
size -= rc;
done += rc;
- progress_tick(done >> 8);
+ progress_tick(done);
}
progress_end();
close(fd);
@@ -690,6 +692,10 @@ static void print_help(const char *pname)
printf("\t\tUsed to ECC clear a partition of the flash\n");
printf("\t\tMust be used in conjunction with -P. Will erase the\n");
printf("\t\tpartition and then set all the ECC bits as they should be\n\n");
+ printf("\t-9 --ecc\n");
+ printf("\t\tEncode/Decode ECC where specified in the FFS header.\n");
+ printf("\t\tThis 9 byte ECC method is used for some OpenPOWER\n");
+ printf("\t\tpartitions.\n");
printf("\t-i, --info\n");
printf("\t\tDisplay some information about the flash.\n\n");
printf("\t--detail\n");
@@ -706,7 +712,8 @@ int main(int argc, char *argv[])
struct flash_details flash = { 0 };
static struct ffs_handle *ffsh = NULL;
uint32_t ffs_index;
- uint32_t address = 0, read_size = 0, write_size = 0, detail_id = UINT_MAX;
+ uint32_t address = 0, read_size = 0, detail_id = UINT_MAX;
+ uint32_t write_size = 0, write_size_minus_ecc = 0;
bool erase = false, do_clear = false;
bool program = false, erase_all = false, info = false, do_read = false;
bool enable_4B = false, disable_4B = false;
@@ -743,11 +750,12 @@ int main(int argc, char *argv[])
{"skip", required_argument, NULL, 'k'},
{"toc", required_argument, NULL, 'T'},
{"clear", no_argument, NULL, 'c'},
+ {"ecc", no_argument, NULL, '9'},
{NULL, 0, NULL, 0 }
};
int c, oidx = 0;
- c = getopt_long(argc, argv, "+:a:s:P:r:43Eep:fdihvbtgS:T:cF:",
+ c = getopt_long(argc, argv, "+:a:s:P:r:43Eep:fdihvbtgS:T:c9F:",
long_opts, &oidx);
if (c == -1)
break;
@@ -862,6 +870,9 @@ int main(int argc, char *argv[])
}
}
break;
+ case '9':
+ flash.mark_ecc = true;
+ break;
case ':':
fprintf(stderr, "Unrecognised option \"%s\" to '%c'\n", optarg, optopt);
no_action = true;
@@ -1052,6 +1063,9 @@ int main(int argc, char *argv[])
write_size = stbuf.st_size;
}
+ /* Only take ECC into account under some conditions later */
+ write_size_minus_ecc = write_size;
+
/* If read specified and no read_size, use flash size */
if (do_read && !read_size && !part_name)
read_size = flash.total_size;
@@ -1095,18 +1109,27 @@ int main(int argc, char *argv[])
/* Read size is obtained from partition "actual" size */
if (!read_size)
read_size = pactsize;
+ /* If we're decoding ecc and partition is ECC'd, then adjust */
+ if (ecc && flash.mark_ecc)
+ read_size = ecc_buffer_size_minus_ecc(read_size);
/* Write size is max size of partition */
if (!write_size)
write_size = pmaxsz;
+ /* But write size can take into account ECC as well */
+ if (ecc && flash.mark_ecc)
+ write_size_minus_ecc = ecc_buffer_size_minus_ecc(write_size);
+ else
+ write_size_minus_ecc = write_size;
+
/* Crop write size to partition size if --force was passed */
- if (write_size > pmaxsz && !must_confirm) {
+ if ((write_size_minus_ecc > pmaxsz) && !must_confirm) {
printf("WARNING: Size (%d bytes) larger than partition"
" (%d bytes), cropping to fit\n",
write_size, pmaxsz);
write_size = pmaxsz;
- } else if (write_size > pmaxsz) {
+ } else if (write_size_minus_ecc > pmaxsz) {
printf("ERROR: Size (%d bytes) larger than partition"
" (%d bytes). Use --force to force\n",
write_size, pmaxsz);
@@ -1169,7 +1192,7 @@ int main(int argc, char *argv[])
rc = erase_range(&flash, address, write_size,
program, ffsh, ffs_index);
if (!rc && program)
- rc = program_file(flash.bl, write_file, address, write_size,
+ rc = program_file(flash.bl, write_file, address, write_size_minus_ecc,
ffsh, ffs_index);
if (!rc && do_clear)
rc = set_ecc(&flash, address, write_size);
diff --git a/external/pflash/test/results/00-usage.out b/external/pflash/test/results/00-usage.out
index caf7b8d..a3721ca 100644
--- a/external/pflash/test/results/00-usage.out
+++ b/external/pflash/test/results/00-usage.out
@@ -97,6 +97,10 @@ Usage: ./pflash [options] commands...
Must be used in conjunction with -P. Will erase the
partition and then set all the ECC bits as they should be
+ -9 --ecc
+ Encode/Decode ECC where specified in the FFS header.
+ This 9 byte ECC method is used for some OpenPOWER
+ partitions.
-i, --info
Display some information about the flash.
diff --git a/external/pflash/test/results/05-bad-numbers.out b/external/pflash/test/results/05-bad-numbers.out
index 17db665..2a76c28 100644
--- a/external/pflash/test/results/05-bad-numbers.out
+++ b/external/pflash/test/results/05-bad-numbers.out
@@ -97,6 +97,10 @@ Usage: ./pflash [options] commands...
Must be used in conjunction with -P. Will erase the
partition and then set all the ECC bits as they should be
+ -9 --ecc
+ Encode/Decode ECC where specified in the FFS header.
+ This 9 byte ECC method is used for some OpenPOWER
+ partitions.
-i, --info
Display some information about the flash.