/* * (C) Copyright 2009 Marco Stornelli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #ifdef MTD_OLD #include #include #else #define __user /* nothing */ #include #endif #include #include #include #include #define MIN(a, b) (((a) < (b)) ? (a) : (b)) extern unsigned long crc32(unsigned long crc, const char *buf, unsigned int len); static void usage(void); static int image_verify_header(char *ptr, int fd); static int flash_bad_block(int fd, uint8_t mtd_type, loff_t start); char *cmdname; char *devicefile; unsigned int sectorcount = 0; int sflag = 0; unsigned int sectoroffset = 0; unsigned int sectorsize = 0; int cflag = 0; int main (int argc, char **argv) { int fd = -1, err = 0, readbyte = 0, j; struct mtd_info_user mtdinfo; char buf[sizeof(image_header_t)]; int found = 0; cmdname = *argv; while (--argc > 0 && **++argv == '-') { while (*++*argv) { switch (**argv) { case 'c': if (--argc <= 0) usage (); sectorcount = (unsigned int)atoi(*++argv); cflag = 1; goto NXTARG; case 'o': if (--argc <= 0) usage (); sectoroffset = (unsigned int)atoi(*++argv); goto NXTARG; case 's': if (--argc <= 0) usage (); sectorsize = (unsigned int)atoi(*++argv); sflag = 1; goto NXTARG; default: usage (); } } NXTARG: ; } if (argc != 1 || cflag == 0 || sflag == 0) usage(); devicefile = *argv; fd = open(devicefile, O_RDONLY); if (fd < 0) { fprintf (stderr, "%s: Can't open %s: %s\n", cmdname, devicefile, strerror(errno)); exit(EXIT_FAILURE); } err = ioctl(fd, MEMGETINFO, &mtdinfo); if (err < 0) { fprintf(stderr, "%s: Cannot get MTD information: %s\n",cmdname, strerror(errno)); exit(EXIT_FAILURE); } if (mtdinfo.type != MTD_NORFLASH && mtdinfo.type != MTD_NANDFLASH) { fprintf(stderr, "%s: Unsupported flash type %u\n", cmdname, mtdinfo.type); exit(EXIT_FAILURE); } if (sectorsize * sectorcount != mtdinfo.size) { fprintf(stderr, "%s: Partition size (%d) incompatible with " "sector size and count\n", cmdname, mtdinfo.size); exit(EXIT_FAILURE); } if (sectorsize * sectoroffset >= mtdinfo.size) { fprintf(stderr, "%s: Partition size (%d) incompatible with " "sector offset given\n", cmdname, mtdinfo.size); exit(EXIT_FAILURE); } if (sectoroffset > sectorcount - 1) { fprintf(stderr, "%s: Sector offset cannot be grater than " "sector count minus one\n", cmdname); exit(EXIT_FAILURE); } printf("Searching....\n"); for (j = sectoroffset; j < sectorcount; ++j) { if (lseek(fd, j*sectorsize, SEEK_SET) != j*sectorsize) { fprintf(stderr, "%s: lseek failure: %s\n", cmdname, strerror(errno)); exit(EXIT_FAILURE); } err = flash_bad_block(fd, mtdinfo.type, j*sectorsize); if (err < 0) exit(EXIT_FAILURE); if (err) continue; /* Skip and jump to next */ readbyte = read(fd, buf, sizeof(image_header_t)); if (readbyte != sizeof(image_header_t)) { fprintf(stderr, "%s: Can't read from device: %s\n", cmdname, strerror(errno)); exit(EXIT_FAILURE); } if (fdt_check_header(buf)) { /* old-style image */ if (image_verify_header(buf, fd)) { found = 1; image_print_contents((image_header_t *)buf); } } else { /* FIT image */ fit_print_contents(buf); } } close(fd); if(!found) printf("No images found\n"); exit(EXIT_SUCCESS); } void usage() { fprintf (stderr, "Usage:\n" " %s [-o offset] -s size -c count device\n" " -o ==> number of sectors to use as offset\n" " -c ==> number of sectors\n" " -s ==> size of sectors (byte)\n", cmdname); exit(EXIT_FAILURE); } static int image_verify_header(char *ptr, int fd) { int len, nread; char *data; uint32_t checksum; image_header_t *hdr = (image_header_t *)ptr; char buf[PAGE_SIZE]; if (image_get_magic(hdr) != IH_MAGIC) return 0; data = (char *)hdr; len = image_get_header_size(); checksum = image_get_hcrc(hdr); hdr->ih_hcrc = htonl(0); /* clear for re-calculation */ if (crc32(0, data, len) != checksum) { fprintf(stderr, "%s: Maybe image found but it has bad header checksum!\n", cmdname); return 0; } len = image_get_size(hdr); checksum = 0; while (len > 0) { nread = read(fd, buf, MIN(len,PAGE_SIZE)); if (nread != MIN(len,PAGE_SIZE)) { fprintf(stderr, "%s: Error while reading: %s\n", cmdname, strerror(errno)); exit(EXIT_FAILURE); } checksum = crc32(checksum, buf, nread); len -= nread; } if (checksum != image_get_dcrc(hdr)) { fprintf (stderr, "%s: Maybe image found but it has corrupted data!\n", cmdname); return 0; } return 1; } /* * Test for bad block on NAND, just returns 0 on NOR, on NAND: * 0 - block is good * > 0 - block is bad * < 0 - failed to test */ static int flash_bad_block(int fd, uint8_t mtd_type, loff_t start) { if (mtd_type == MTD_NANDFLASH) { int badblock = ioctl(fd, MEMGETBADBLOCK, &start); if (badblock < 0) { fprintf(stderr,"%s: Cannot read bad block mark: %s\n", cmdname, strerror(errno)); return badblock; } if (badblock) { return badblock; } } return 0; }