Here is a patch, which is mostly a slightly modified version of KSI's patch to enable correct OOB placement in the yaffs2 image, but with the addition of calculating the ECC checksums and putting them in the correct place as well. This is useful if doing large production runs where the NAND chips will be programmed in advance. Or if trying to program the NAND chips using a JTAG programmer etc... It isn't a particularly clean patch, and it does #ifdef out the support for endian swapping, but it certainly appears to be working for me. Thanks, Andre Index: mkyaffs2image.c =================================================================== RCS file: /home/aleph1/cvs/yaffs2/utils/mkyaffs2image.c,v retrieving revision 1.4 diff -u -w -r1.4 mkyaffs2image.c --- mkyaffs2image.c 14 Feb 2007 01:09:06 -0000 1.4 +++ mkyaffs2image.c 20 Sep 2007 22:17:16 -0000 @@ -19,6 +19,23 @@ * * Makes a YAFFS2 file system image that can be used to load up a file system. * Uses default Linux MTD layout - change if you need something different. + * + * Changes by Sergey Kubushin flagged KSI + * + */ + +/* KSI: + * All this nightmare should be rewritten from ground up. Why save return + * values if nobody checks them? The read/write function returns only one + * error, -1. Positive return value does NOT mean read/write operation has + * been completed successfully. If somebody opens files, he MUST close them + * when they are not longer needed. Only those brave enough can write 64 + * bytes from a yaffs_PackedTags2 structure. The list is too long, there is + * enough bugs here to write a couple of thick books on how NOT to write + * programs... + * + * And BTW, what was one supposed to do with that file that this horror + * occasionally managed to generate? */ #include @@ -29,10 +46,11 @@ #include #include #include +#define __user +#include #include "yaffs_ecc.h" #include "yaffs_guts.h" -#include "yaffs_tagsvalidity.h" #include "yaffs_packedtags2.h" unsigned yaffs_traceMask=0; @@ -41,9 +59,45 @@ #define chunkSize 2048 #define spareSize 64 +#define PT2_BYTES 25 const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.4 2007-02-14 01:09:06 wookey Exp $"; +static int layout_no; + +static struct nand_oobinfo oob_layout[] = { + /* KSI: + * Dummy "raw" layout - no ECC, all the bytes are free. Does NOT + * really work, only used for compatibility with CVS YAFFS2 that + * never ever worked with any stock MTD. + */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 0, + .eccpos = {}, + .oobfree = { {0, 64} } + }, + /* KSI: + * Regular MTD AUTOPLACED ECC for large page NAND devices, the + * only one existing in stock MTD so far. It corresponds to layout# 1 + * in command line arguments. Any other layouts could be added to + * the list when they made their way in kernel's MTD. The structure + * is simply copied from kernel's drivers/mtd/nand/nand_base.c as-is. + */ + { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { {2, 38} } + }, + /* End-of-list marker */ + { + .useecc = -1, + } +}; typedef struct { @@ -57,7 +111,7 @@ static int n_obj = 0; static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; -static int nObjects, nDirectories, nPages; +static int nObjects = 0, nDirectories = 0, nPages = 0; static int outFile; @@ -121,6 +175,35 @@ return -1; } +/** + * Calculate the ECC using the YAFFS internal functions, + * and then put it into the oob buffer in the correct place + */ +static void yaffs_PutDataECC(const __u8 * data, unsigned char *oob_buf) +{ + unsigned char ecc_code[3]; + int eccsteps = chunkSize / 256; + int eccidx = 0, datidx = 0, i; + struct nand_oobinfo *oobsel; + __u32 *oob_config; + + oobsel = &oob_layout[layout_no]; + oob_config = oobsel->eccpos; + + for (; eccsteps; eccsteps--) { + yaffs_ECCCalculate (&data[datidx], ecc_code); + for (i = 0; i < 3; i++, eccidx++) + oob_buf[oob_config[eccidx]] = ecc_code[i]; + datidx += 256; + } +} + + +/* KSI: + * No big endian for now. This is left for a later time. The existing code + * is FUBAR. + */ +#if 0 /* This little function converts a little endian tag to a big endian tag. * NOTE: The tag is not usable after this other than calculating the CRC * with. @@ -153,11 +236,55 @@ tags->asBytes[7] = temp.asBytes[7]; #endif } +#endif + +static void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt) +{ + int i, j = 0, k, n; + unsigned char pt2_byte_buf[PT2_BYTES]; + + *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber; + *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId; + *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId; + *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount; + pt2_byte_buf[16] = pt->ecc.colParity; + pt2_byte_buf[17] = pt->ecc.lineParity & 0xff; + pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff; + pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff; + pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff; + pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff; + pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; + pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; + pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; + + k = oob_layout[layout_no].oobfree[j][0]; + n = oob_layout[layout_no].oobfree[j][1]; + + if (n == 0) { + fprintf(stderr, "No OOB space for tags"); + exit(-1); + } + + for (i = 0; i < PT2_BYTES; i++) { + if (n == 0) { + j++; + k = oob_layout[layout_no].oobfree[j][0]; + n = oob_layout[layout_no].oobfree[j][1]; + if (n == 0) { + fprintf(stderr, "No OOB space for tags"); + exit(-1); + } + } + buf[k++] = pt2_byte_buf[i]; + n--; + } +} static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) { yaffs_ExtendedTags t; yaffs_PackedTags2 pt; + unsigned char spare_buf[spareSize]; error = write(outFile,data,chunkSize); if(error < 0) return error; @@ -175,18 +302,29 @@ // added NCB **CHECK** t.chunkUsed = 1; +/* KSI: Broken anyway -- e.g. &t is pointer to a wrong type... */ +#if 0 if (convert_endian) { little_to_big_endian(&t); } +#endif nPages++; yaffs_PackTags2(&pt,&t); -// return write(outFile,&pt,sizeof(yaffs_PackedTags2)); - return write(outFile,&pt,spareSize); + memset(spare_buf, 0xff, sizeof(spare_buf)); + + if (layout_no == 0) { + memcpy(spare_buf, &pt, sizeof(yaffs_PackedTags2)); + } else { + nandmtd2_pt2buf(spare_buf, &pt); + } + + yaffs_PutDataECC(data, &spare_buf[0]); + return write(outFile,spare_buf,spareSize); } #define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ @@ -197,6 +335,8 @@ #define SWAP16(x) ((((x) & 0x00FF) << 8) | \ (((x) & 0xFF00) >> 8)) +/* KSI: Removed for now. TBD later when the proper util (from scratch) is written */ +#if 0 // This one is easier, since the types are more standard. No funky shifts here. static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) { @@ -254,6 +394,7 @@ oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); #endif } +#endif static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) { @@ -298,10 +439,13 @@ strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); } +/* KSI: FUBAR. Left for a leter time. */ +#if 0 if (convert_endian) { object_header_little_to_big_endian(oh); } +#endif return write_chunk(bytes,objId,0,0xffff); @@ -401,12 +545,12 @@ error = nBytes; printf("%d data chunks written\n",chunk); + close(h); } else { perror("Error opening file"); } - close(h); } @@ -446,58 +590,82 @@ } } } + /* KSI: + * Who is supposed to close those open directories in this + * recursive function, lord Byron? Stock "ulimit -n" is 1024 + * and e.g. stock Fedora /etc directory has more that 1024 + * directories... + */ + closedir(dir); } return 0; } +static void usage(void) +{ + printf("usage: mkyaffs2image layout# dir image_file [convert]\n"); + printf(" layout# NAND OOB layout # (0 - raw, 1 - nand_oob_64)\n"); + printf(" dir the directory tree to be converted\n"); + printf(" image_file the output file to hold the image\n"); + printf(" 'convert' make a big-endian img on a little-endian machine. BROKEN !\n"); + exit(1); +} int main(int argc, char *argv[]) { struct stat stats; + int i; printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); - if(argc < 3) + if ((argc < 4) || (sscanf(argv[1], "%u", &layout_no) != 1)) { - printf("usage: mkyaffs2image dir image_file [convert]\n"); - printf(" dir the directory tree to be converted\n"); - printf(" image_file the output file to hold the image\n"); - printf(" 'convert' produce a big-endian image from a little-endian machine\n"); - exit(1); + usage(); } - if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) + i = 0; + + while (oob_layout[i].useecc != -1) + i++; + + if (layout_no >= i) + usage(); + + if ((argc == 5) && (!strncmp(argv[4], "convert", strlen("convert")))) { + /* KSI: Broken as of now. TBD. Fail. */ + usage(); convert_endian = 1; } - if(stat(argv[1],&stats) < 0) + if(stat(argv[2],&stats) < 0) { - printf("Could not stat %s\n",argv[1]); + printf("Could not stat %s\n",argv[2]); exit(1); } if(!S_ISDIR(stats.st_mode)) { - printf(" %s is not a directory\n",argv[1]); + printf(" %s is not a directory\n",argv[2]); exit(1); } - outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); + outFile = open(argv[3],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); if(outFile < 0) { - printf("Could not open output file %s\n",argv[2]); + printf("Could not open output file %s\n",argv[3]); exit(1); } - printf("Processing directory %s into image file %s\n",argv[1],argv[2]); + printf("Processing directory %s into image file %s\n",argv[2],argv[3]); error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); + if(error) - error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); + error = process_directory(YAFFS_OBJECTID_ROOT,argv[2]); close(outFile); -- Bluewater Systems Ltd - ARM Technology Solutions Centre Andre Renaud Bluewater Systems Ltd Phone: +64 3 3779127 (Aus 1 800 148 751) Level 17, 119 Armagh St Fax: +64 3 3779135 PO Box 13889 Email: arenaud@bluewatersys.com Christchurch Web: http://www.bluewatersys.com New Zealand