diff options
Diffstat (limited to 'nftldump.c')
-rw-r--r-- | nftldump.c | 278 |
1 files changed, 0 insertions, 278 deletions
diff --git a/nftldump.c b/nftldump.c deleted file mode 100644 index 32f4f2f..0000000 --- a/nftldump.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk" - * - * 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 - * - * ToDo: - * 1. UnitSizeFactor != 0xFF cases - * 2. test, test, and test !!! - */ - -#define PROGRAM_NAME "nftldump" - -#define _XOPEN_SOURCE 500 /* For pread */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <errno.h> - -#include <sys/ioctl.h> -#include <asm/types.h> -#include <mtd/mtd-user.h> -#include <mtd/nftl-user.h> -#include <mtd_swab.h> - -static struct NFTLMediaHeader MedHead[2]; -static mtd_info_t meminfo; - -static struct nftl_oob oobbuf; -static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf}; - -static int fd, ofd = -1;; -static int NumMedHeads; - -static unsigned char BadUnitTable[MAX_ERASE_ZONES]; - -#define SWAP16(x) do { x = le16_to_cpu(x); } while(0) -#define SWAP32(x) do { x = le32_to_cpu(x); } while(0) - -/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */ -static unsigned short *VUCtable; - -/* FixMe: make this dynamic allocated */ -#define ERASESIZE 0x2000 -#define NUMVUNITS ((40*1024*1024) / ERASESIZE) -static union nftl_uci UCItable[NUMVUNITS][3]; - -static unsigned short nextEUN(unsigned short curEUN) -{ - return UCItable[curEUN][0].a.ReplUnitNum; -} - -static unsigned int find_media_headers(void) -{ - int i; - static unsigned long ofs = 0; - - NumMedHeads = 0; - while (ofs < meminfo.size) { - pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs); - if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) { - SWAP16(MedHead[NumMedHeads].NumEraseUnits); - SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN); - SWAP32(MedHead[NumMedHeads].FormattedSize); - - if (NumMedHeads == 0) { - printf("NFTL Media Header found at offset 0x%08lx:\n", ofs); - printf("NumEraseUnits: %d\n", - MedHead[NumMedHeads].NumEraseUnits); - printf("FirstPhysicalEUN: %d\n", - MedHead[NumMedHeads].FirstPhysicalEUN); - printf("Formatted Size: %d\n", - MedHead[NumMedHeads].FormattedSize); - printf("UnitSizeFactor: 0x%x\n", - MedHead[NumMedHeads].UnitSizeFactor); - - /* read BadUnitTable, I don't know why pread() does not work for - larger (7680 bytes) chunks */ - for (i = 0; i < MAX_ERASE_ZONES; i += 512) - pread(fd, &BadUnitTable[i], 512, ofs + 512 + i); - } else - printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs); - NumMedHeads++; - } - - ofs += meminfo.erasesize; - if (NumMedHeads == 2) { - if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) { - printf("warning: NFTL Media Header is not consistent with " - "Spare NFTL Media Header\n"); - } - break; - } - } - - /* allocate Virtual Unit Chain table for this NFTL partition */ - VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short)); - return NumMedHeads; -} - -static void dump_erase_units(void) -{ - int i, j; - unsigned long ofs; - - for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN + - MedHead[0].NumEraseUnits; i++) { - /* For each Erase Unit */ - ofs = i * meminfo.erasesize; - - /* read the Unit Control Information */ - for (j = 0; j < 3; j++) { - oob.start = ofs + (j * 512); - if (ioctl(fd, MEMREADOOB, &oob)) - printf("MEMREADOOB at %lx: %s\n", - (unsigned long) oob.start, strerror(errno)); - memcpy(&UCItable[i][j], &oobbuf.u, 8); - } - if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) { - printf("EraseMark not present in unit %d: %x\n", - i, UCItable[i][1].b.EraseMark); - } else { - /* a properly formatted unit */ - SWAP16(UCItable[i][0].a.VirtUnitNum); - SWAP16(UCItable[i][0].a.ReplUnitNum); - SWAP16(UCItable[i][0].a.SpareVirtUnitNum); - SWAP16(UCItable[i][0].a.SpareReplUnitNum); - SWAP32(UCItable[i][1].b.WearInfo); - SWAP16(UCItable[i][1].b.EraseMark); - SWAP16(UCItable[i][1].b.EraseMark1); - SWAP16(UCItable[i][2].c.FoldMark); - SWAP16(UCItable[i][2].c.FoldMark1); - - if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) { - /* If this is the first in a chain, store the EUN in the VUC table */ - if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) { - printf("Duplicate start of chain for VUC %d: " - "Unit %d replaces Unit %d\n", - UCItable[i][0].a.VirtUnitNum & 0x7fff, - i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]); - } - VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i; - } - } - - switch (BadUnitTable[i]) { - case ZONE_BAD_ORIGINAL: - printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i); - continue; - case ZONE_BAD_MARKED: - printf("Unit %d is marked as ZONE_BAD_MARKED\n", i); - continue; - } - - /* ZONE_GOOD */ - if (UCItable[i][0].a.VirtUnitNum == 0xffff) - printf("Unit %d is free\n", i); - else - printf("Unit %d is in chain %d and %s a replacement\n", i, - UCItable[i][0].a.VirtUnitNum & 0x7fff, - UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not"); - } -} - -static void dump_virtual_units(void) -{ - int i, j; - char readbuf[512]; - - for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) { - unsigned short curEUN = VUCtable[i]; - - printf("Virtual Unit #%d: ", i); - if (!curEUN) { - printf("Not present\n"); - continue; - } - printf("%d", curEUN); - - /* walk through the Virtual Unit Chain */ - while ((curEUN = nextEUN(curEUN)) != 0xffff) { - printf(", %d", curEUN & 0x7fff); - } - printf("\n"); - - if (ofd != -1) { - /* Actually write out the data */ - for (j = 0; j < meminfo.erasesize / 512; j++) { - /* For each sector in the block */ - unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i]; - unsigned int status; - - if (thisEUN == 0xffff) thisEUN = 0; - - while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) { - oob.start = (thisEUN * ERASESIZE) + (j * 512); - ioctl(fd, MEMREADOOB, &oob); - status = oobbuf.b.Status | oobbuf.b.Status1; - - switch (status) { - case SECTOR_FREE: - /* This is still free. Don't look any more */ - thisEUN = 0; - break; - - case SECTOR_USED: - /* SECTOR_USED. This is a good one. */ - lastgoodEUN = thisEUN; - break; - } - - /* Find the next erase unit in this chain, if any */ - if (thisEUN) - thisEUN = nextEUN(thisEUN) & 0x7fff; - } - - if (lastgoodEUN == 0xffff) - memset(readbuf, 0, 512); - else - pread(fd, readbuf, 512, - (lastgoodEUN * ERASESIZE) + (j * 512)); - - write(ofd, readbuf, 512); - } - - } - } -} - -int main(int argc, char **argv) -{ - if (argc < 2) { - printf("Usage: %s <device> [<outfile>]\n", PROGRAM_NAME); - exit(1); - } - fd = open(argv[1], O_RDONLY); - if (fd == -1) { - perror("open flash"); - exit (1); - } - - if (argc > 2) { - ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); - if (ofd == -1) - perror ("open outfile"); - } - - /* get size information of the MTD device */ - if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { - perror("ioctl(MEMGETINFO)"); - close(fd); - return 1; - } - - while (find_media_headers() != 0) { - dump_erase_units(); - dump_virtual_units(); - free(VUCtable); - } - - exit(0); -} |