کد:
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 0x210 // Size of page buffer
#define MAX_BLOCKS 0x1000 // Max number of blocks for bad and reloc block map
#define XEN_BLOCKNUM 0x200 // Xenon block number page offset
#define JAS_BLOCKNUM 0x201 // Jasper block number page offset
#define BB_BBFLAG 0x200 // BigBlock: Bad block flag page offset
#define BB_PAGES 0x100 // BigBlock: Number of ECC pages in a block
#define BB_PSIZE 0x210 // BigBlock: Number of bytes in a page
#define BB_BSIZE (BB_PSIZE * BB_PAGES) // BigBlock: Number of bytes in a block
#define SB_BBFLAG 0x205 // SmallBlock: Bad block flag page offset
#define SB_PAGES 0x020 // SmallBlock: Number of ECC pages in a block
#define SB_PSIZE 0x210 // SmallBlock: Number of bytes in a page
#define SB_BSIZE (SB_PSIZE * SB_PAGES) // SmallBlock: Number of bytes in a block
/* Some macros to clean up the code */
#define SETBIT(map,bit) ((map)[(bit)>>3] |= 1 << ((bit) & 7))
#define GETBIT(map,bit) ((map)[(bit)>>3] >> ((bit) & 7) & 1)
#define BBFLAG(bb) ((bb) ? BB_BBFLAG : SB_BBFLAG)
#define PAGES(bb) ((bb) ? BB_PAGES : SB_PAGES)
#define PSIZE(bb) ((bb) ? BB_PSIZE : SB_PSIZE)
#define BSIZE(bb) ((bb) ? BB_BSIZE : SB_BSIZE)
#define BLOCKNUM(jas) ((jas) ? JAS_BLOCKNUM: XEN_BLOCKNUM)
void printUsage(const char *p) {
printf("Nandcheck v0.23\n");
printf("Usage: %s [-b] <filename>\n",p);
printf(" -b: Use big block mode for 256MB+ NAND flash chips\n");
printf(" -j: Use Jasper block numbering (implied with -b)\n");
}
void calcecc(unsigned long *data, unsigned char *ecc)
{
int i=0, val=0;
unsigned long v;
for (i = 0; i < 0x1066; i++) {
if (!(i & 31))
v = ~data[i>>5];
val ^= v & 1;
v >>= 1;
if (val & 1)
val ^= 0x6954559;
val >>= 1;
}
val = ~val;
ecc[0] = (val << 6) & 0xFF;
ecc[1] = (val >> 2) & 0xFF;
ecc[2] = (val >> 10) & 0xFF;
ecc[3] = (val >> 18) & 0xFF;
}
int main (int argc, const char * argv[]) {
unsigned char data[BUFF_SIZE], badmap[MAX_BLOCKS/8], relocmap[MAX_BLOCKS/8], ecc[4];
unsigned int i,j,k,blocks,temp;
unsigned int bb=0,jas=0,numBad=0,numEmpty=0,numECC=0,reloc=0;
FILE *fp;
/* Check Args */
if((argc < 2) || (argc > 4)) {
printUsage(*argv);
return 1;
}
/* Parse options */
for(i=1;i<argc-1;i++) {
if(strlen(argv[i])== 2 && argv[i][0] == '-') {
switch (argv[i][1]) {
case 'b':
bb++;
jas++;
break;
case 'j':
jas++;
break;
default:
printUsage(*argv);
return 1;
}
} else {
printUsage(*argv);
return 1;
}
}
/* Try to open the file */
if((fp=fopen(argv[argc-1], "rb")) == NULL) {
printf("Error opening %s\n",argv[argc-1]);
return 1;
}
/* Check if the file size makes sense */
fseek(fp, 0, SEEK_END);
blocks=ftell(fp);
fseek(fp, 0, SEEK_SET);
if(blocks % BSIZE(bb)) {
printf("Warning: File size is not a multiple of the raw block size.\n");
printf(" Last block fragment will not be checked\n\n");
}
blocks/= BSIZE(bb);
printf("File %s contains 0x%03X blocks.\n",argv[argc-1],blocks);
if(blocks > MAX_BLOCKS) {
printf("Warning: Blocks above %d will not be considered in the bad block summary,\n",MAX_BLOCKS);
printf(" or checked for relocation.\n");
}
/* Determine if complete */
if(bb) {
switch (blocks) {
case 0x800:
printf("File size matches a big block 256MB NAND flash.\n");
break;
case 0x1000:
printf("File size matches a big block 512MB NAND flash.\n");
break;
default:
printf("File size does not match known big block NAND flash sizes.\n");
}
} else {
if (blocks == 0x400) {
printf("File size matches a small block 16MB NAND flash.\n");
} else {
printf("File size does not match known small block NAND flash sizes.\n");
}
}
/* Clear map arrays */
memset(badmap, 0, sizeof(badmap));
memset(relocmap, 0, sizeof(relocmap));
/* Start the Block and Page loops */
for(i=0;i<blocks;i++) {
reloc=0;
for(j=0;j<PAGES(bb);j++) {
fread(data, 1, PSIZE(bb), fp); // Read in the page
/* Check if empty */
temp=0xFF;
for(k=0;k<PSIZE(bb);temp&=data[k++]);
if(temp == 0xFF) {
numEmpty++;
continue; // No need for further checks
}
/* Check for bad block per Hynix datasheet. */
if(data[BBFLAG(bb)] != 0xFF) {
printf("Bad block:page %03X:%02X\n",i,j);
numBad++;
SETBIT(badmap,i);
continue; // No need for further checks
}
/* Check block number in spare data. A mismatch may be a relocation. */
if(!reloc) {
temp=*(int *)(data+BLOCKNUM(jas)) & 0xFFFF;
if(i != temp) {
printf("Block number mismatch in block:page %03X:%02X -> %03X vs %03X\n", \
i,j,temp,i);
if (temp < MAX_BLOCKS) {
if (GETBIT(badmap,temp)) {
printf(" This block is probably a relocation of bad block %03X.\n",temp);
printf(" Skipping relocation warnings for the rest of the block.\n");
reloc++;
SETBIT(relocmap,temp);
}
}
}
}
/* Calc the ECC data and compare */
calcecc((unsigned long *) data, ecc);
ecc[0] |= data[PSIZE(bb)-4] & 0x3F; // These 6 bits are not part of the ECC
if(memcmp(data+PSIZE(bb)-4,ecc,4)) {
printf("ECC mismatch in block:page %03X:%02X -> 0x%08X vs 0x%08X\n", \
i,j,*(unsigned long *)(data+0x20c),*(unsigned long *)ecc);
numECC++;
}
}
}
fclose(fp);
printf("\nCheck complete!\n");
if(numBad) {
printf("Found the following bad blocks (* marked blocks have been relocated):\n ");
for(i=0,j=0;i<MAX_BLOCKS;i++) {
if(GETBIT(badmap,i)) {
printf("%c%03X ",GETBIT(relocmap,i)?'*':' ',i);
j++;
}
if(j >= 10) {
printf("\n ");
j=0;
}
}
}
printf("\nFound %d ECC error(s), %d bad page(s), %d empty page(s).\n",numECC,numBad,numEmpty);
return 0;
}