下面是修改后的mkyaffs2image.c,使其生成的makeyaffs2image支持2k/4k/8k pagesize的nand flash:
———————————mkyaffs2image.c的源码———————————-
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
* Nick Bane modifications flagged NCB
* Endian handling patches by James Ng.
* mkyaffs2image hacks by NCB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* makeyaffs2image.c
*
* 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.
* Added support for 2k/4k/8k pagesize nand flash by green-waste@163.com
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include "yaffs_ecc.h"
#include "yaffs_guts.h"
#include "yaffs_tagsvalidity.h"
#include "yaffs_packedtags2.h"
unsigned yaffs_traceMask = 0;
#define MAX_OBJECTS 10000
#define CHUNKSIZE_2K 2048
#define SPARESIZE_64 64
#define CHUNKSIZE_4K 4096
#define SPARESIZE_128 128
#define CHUNKSIZE_8K 8192
#define SPARESIZE_256 256
#define MAX_CHUNKSIZE CHUNKSIZE_8K
#define MAX_SPARESIZE SPARESIZE_256
#define ALL_0xFF_U32 (0xFFFFFFFF)
const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.5 2010/01/11 21:43:18 charles Exp $";
typedef struct
{
dev_t dev;
ino_t ino;
int obj;
} objItem;
static objItem obj_list[MAX_OBJECTS];
static int n_obj = 0;
static int obj_id = YAFFS_NOBJECT_BUCKETS + 1;
static int nObjects, nDirectories, nPages;
static int outFile;
static int error;
static int convert_endian = 0; /* default is little endian */
static int ecc_on_tag = 1; /* default is do ECC on packed tags for yaffs2 */
static int chunk_size = CHUNKSIZE_2K;
static int spare_size = SPARESIZE_64;
/*
* follow are current use oob(spare) layout in Linux Kernel MTD, nand_base.c:
* static struct nand_ecclayout nand_oob_64 = {
* ……
* .oobfree = {
* {.offset = 2,
* .length = 30}}
* };
*
* static struct nand_ecclayout nand_oob_128 = {
* ……
* .oobfree = {
* {.offset = 2,
* .length = 62}}
* };
*
* that means the oob free for yaffs2 use is from 2~31 for 2K page nand or 2~61 for 4K page nand …
* and yaffs2 tag is sizeof(yaffs_PackedTags2) = 25 or 16(no tag ecc)
* is enough for yaffs2 use, and START OFFSET is 2.
* here just to make sure is correpondding with Linux Kernel
*/
static int yaffs2_tag_start_position_in_spare = 2;
#define SWAP32( x ) ( ( ( (x) & 0x000000FF) << 24) |
( ( (x) & 0x0000FF00) << 8) |
( ( (x) & 0x00FF0000) >> 8) |
( ( (x) & 0xFF000000) >> 24) )
#define SWAP16( x ) ( ( ( (x) & 0x00FF) << 8) |
( ( (x) & 0xFF00) >> 8) )
static int obj_compare( const void *a, const void * b )
{
objItem *oa, *ob;
oa = (objItem *) a;
ob = (objItem *) b;
if ( oa->dev < ob->dev )
return(-1);
if ( oa->dev > ob->dev )
return(1);
if ( oa->ino < ob->ino )
return(-1);
if ( oa->ino > ob->ino )
return(1);
return(0);
}
static void add_obj_to_list( dev_t dev, ino_t ino, int obj )
{
if ( n_obj < MAX_OBJECTS )
{
obj_list[n_obj].dev = dev;
obj_list[n_obj].ino = ino;
obj_list[n_obj].obj = obj;
n_obj++;
qsort( obj_list, n_obj, sizeof(objItem), obj_compare );
}else {
/* oops! not enough space in the object array */
fprintf( stderr, "Not enough space in object arrayn" );
exit( 2 );
}
}
static int find_obj_in_list( dev_t dev, ino_t ino )
{
objItem *i = NULL;
objItem test;
test.dev = dev;
test.ino = ino;
if ( n_obj > 0 )
{
i = bsearch( &test, obj_list, n_obj, sizeof(objItem), obj_compare );
}
if ( i )
{
return(i->obj);
}
return(-1);
}
/* This little function converts a little endian tag to a big endian tag.*/
static void little_to_big_endian_yaffs2PackedTagTagsPart( yaffs_PackedTags2TagsPart *tagsPtr )
{
tagsPtr->sequenceNumber = SWAP32( tagsPtr->sequenceNumber );
tagsPtr->objectId = SWAP32( tagsPtr->objectId );
tagsPtr->chunkId = SWAP32( tagsPtr->chunkId );
tagsPtr->byteCount = SWAP32( tagsPtr->byteCount );
}
static void little_to_big_endian_yaffs2PackedTagECCPart( yaffs_ECCOther *eccPtr )
{
/* colParity is unsigned char, not need swap */
eccPtr->lineParity = SWAP32( eccPtr->lineParity );
eccPtr->lineParityPrime = SWAP32( eccPtr->lineParityPrime );
}
#if 0
static void yaffs_PackTags2_auto_endian( yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t, int tagsECC, int big_endian )
{
yaffs_PackTags2TagsPart( &pt->t, t );
/*
* if (big_endian)
* {
* little_to_big_endian_yaffs2PackedTagTagsPart(&pt->t);
* }
*/
if ( tagsECC )
{
yaffs_ECCCalculateOther( (unsigned char *) &pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc );
if ( big_endian )
{
little_to_big_endian_yaffs2PackedTagECCPart( &pt->ecc );
}
}
}
#endif
static int write_chunk( __u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes )
{
yaffs_ExtendedTags t;
yaffs_PackedTags2 pt;
int tag_size = ecc_on_tag ? sizeof(yaffs_PackedTags2) : sizeof(yaffs_PackedTags2TagsPart);
__u8 spare_buf[MAX_SPARESIZE]; /* max enough */
error = write( outFile, data, chunk_size );
if ( error < 0 )
return(error);
yaffs_InitialiseTags( &t );
t.chunkId = chunkId;
/* t.serialNumber = 0; */
/*CRL: seems not need this,
* for yaffs2, in yaffs_UnpackTags2TagsPart() will do "t->serialNumber = 0;"
* and this field is not used for yaffs2 */
/* t.serialNumber = 1; // **CHECK** */
t.byteCount = nBytes;
t.objectId = objId;
t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
/* added NCB **CHECK** */
/* CRL: seems that not need this, for in yaffs_UnpackTags2TagsPart(),
* when found (ptt->sequenceNumber != 0xFFFFFFFF), here has set to YAFFS_LOWEST_SEQUENCE_NUMBER,
* then will do "t->chunkUsed = 1;" */
/* t.chunkUsed = 1; */
nPages++;
/* CRL: add little to big endian if need */
yaffs_PackTags2( &pt, &t, ecc_on_tag );
if ( convert_endian )
{
little_to_big_endian_yaffs2PackedTagTagsPart( &pt.t );
if ( ecc_on_tag )
{
little_to_big_endian_yaffs2PackedTagECCPart( &pt.ecc );
}
}
/* prepare spare buffer */
memset( spare_buf, 0xFF, spare_size );
/* copy yaffs2 tag into spare */
memcpy( spare_buf + yaffs2_tag_start_position_in_spare, &pt, tag_size );
return(write( outFile, spare_buf, spare_size ) );
}
/* This one is easier, since the types are more standard. No funky shifts here. */
static void yaffs2_object_header_little_to_big_endian( yaffs_ObjectHeader* oh )
{
oh->type = SWAP32( oh->type ); /* GCC makes enums 32 bits. */
oh->parentObjectId = SWAP32( oh->parentObjectId ); /* int */
oh->sum__NoLongerUsed = SWAP16( oh->sum__NoLongerUsed ); /* __u16 – Not used, but done for completeness. */
/* name = skip. Char array. Not swapped. */
oh->yst_mode = SWAP32( oh->yst_mode );
#ifdef CONFIG_YAFFS_WINCE /* WinCE doesn’t implement this, but we need to just in case. */
/* In fact, WinCE would be *THE* place where this would be an issue! */
oh->notForWinCE[0] = SWAP32( oh->notForWinCE[0] );
oh->notForWinCE[1] = SWAP32( oh->notForWinCE[1] );
oh->notForWinCE[2] = SWAP32( oh->notForWinCE[2] );
oh->notForWinCE[3] = SWAP32( oh->notForWinCE[3] );
oh->notForWinCE[4] = SWAP32( oh->notForWinCE[4] );
#else
/* Regular POSIX. */
oh->yst_uid = SWAP32( oh->yst_uid );
oh->yst_gid = SWAP32( oh->yst_gid );
oh->yst_atime = SWAP32( oh->yst_atime );
oh->yst_mtime = SWAP32( oh->yst_mtime );
oh->yst_ctime = SWAP32( oh->yst_ctime );
#endif
oh->fileSize = SWAP32( oh->fileSize ); /* Aiee. An int… signed, at that! */
oh->equivalentObjectId = SWAP32( oh->equivalentObjectId );
/* alias – char array. */
oh->yst_rdev = SWAP32( oh->yst_rdev );
#ifdef CONFIG_YAFFS_WINCE
oh->win_ctime[0] = SWAP32( oh->win_ctime[0] );
oh->win_ctime[1] = SWAP32( oh->win_ctime[1] );
oh->win_atime[0] = SWAP32( oh->win_atime[0] );
oh->win_atime[1] = SWAP32( oh->win_atime[1] );
oh->win_mtime[0] = SWAP32( oh->win_mtime[0] );
oh->win_mtime[1] = SWAP32( oh->win_mtime[1] );
#else /* no def CONFIG_YAFFS_WINCE */
oh->roomToGrow[0] = SWAP32( oh->roomToGrow[0] );
oh->roomToGrow[1] = SWAP32( oh->roomToGrow[1] );
oh->roomToGrow[2] = SWAP32( oh->roomToGrow[2] );
oh->roomToGrow[3] = SWAP32( oh->roomToGrow[3] );
oh->roomToGrow[4] = SWAP32( oh->roomToGrow[4] );
oh->roomToGrow[5] = SWAP32( oh->roomToGrow[5] );
#endif
/* CRL: update accord with yaffs_ObjectHeader */
oh->inbandShadowsObject = SWAP32( oh->inbandShadowsObject );
oh->inbandIsShrink = SWAP32( oh->inbandIsShrink );
oh->reservedSpace[0] = SWAP32( oh->reservedSpace[0] );
oh->reservedSpace[1] = SWAP32( oh->reservedSpace[1] );
oh->shadowsObject = SWAP32( oh->shadowsObject );
oh->isShrink = SWAP32( oh->isShrink );
}
static int write_object_header( int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias )
{
__u8 bytes[MAX_CHUNKSIZE];
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) bytes;
memset( bytes, 0xFF, chunk_size );
oh->type = t;
oh->parentObjectId = parent;
strncpy( oh->name, name, YAFFS_MAX_NAME_LENGTH );
if ( t != YAFFS_OBJECT_TYPE_HARDLINK )
{
oh->yst_mode = s->st_mode;
oh->yst_uid = s->st_uid;
/* NCB 12/9/02 oh->yst_gid = s->yst_uid; */
oh->yst_gid = s->st_gid;
oh->yst_atime = s->st_atime;
oh->yst_mtime = s->st_mtime;
oh->yst_ctime = s->st_ctime;
oh->yst_rdev = s->st_rdev;
}
if ( t == YAFFS_OBJECT_TYPE_FILE )
{
oh->fileSize = s->st_size;
}
if ( t == YAFFS_OBJECT_TYPE_HARDLINK )
{
oh->equivalentObjectId = equivalentObj;
}
if ( t == YAFFS_OBJECT_TYPE_SYMLINK )
{
strncpy( oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH );
}
if ( convert_endian )
{
yaffs2_object_header_little_to_big_endian( oh );
}
/* CRL:
* chunkid==0 means chunk is object header, not data chunk
* nBytes==0 here, for byteCount Only valid for data chunks */
return(write_chunk( bytes, objId, 0, 0 ) );
}
static int process_directory( int parent, const char *path )
{
DIR *dir;
struct dirent *entry;
nDirectories++;
dir = opendir( path );
if ( dir )
{
while ( (entry = readdir( dir ) ) != NULL )
{
/* Ignore . and .. */
if ( strcmp( entry->d_name, "." ) &&
strcmp( entry->d_name, ".." ) )
{
char full_name[500];
struct stat stats;
int equivalentObj;
int newObj;
sprintf( full_name, "%s/%s", path, entry->d_name );
lstat( full_name, &stats );
if ( S_ISLNK( stats.st_mode ) ||
S_ISREG( stats.st_mode ) ||
S_ISDIR( stats.st_mode ) ||
S_ISFIFO( stats.st_mode ) ||
S_ISBLK( stats.st_mode ) ||
S_ISCHR( stats.st_mode ) ||
S_ISSOCK( stats.st_mode ) )
{
newObj = obj_id++;
nObjects++;
printf( "Object %d, %s is a ", newObj, full_name );
/* We’re going to create an object for it */
if ( (equivalentObj = find_obj_in_list( stats.st_dev, stats.st_ino ) ) > 0 )
{
/* we need to make a hard link */
printf( "hard link to object %dn", equivalentObj );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL );
}else {
add_obj_to_list( stats.st_dev, stats.st_ino, newObj );
if ( S_ISLNK( stats.st_mode ) )
{
char symname[500];
memset( symname, 0, sizeof(symname) );
readlink( full_name, symname, sizeof(symname) - 1 );
printf( "symlink to " % s "n", symname );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname );
}else if ( S_ISREG( stats.st_mode ) )
{
printf( "file, " );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL );
if ( error >= 0 )
{
int h;
__u8 bytes[MAX_CHUNKSIZE];
int nBytes;
int chunk = 0;
h = open( full_name, O_RDONLY );
if ( h >= 0 )
{
memset( bytes, 0xff, chunk_size );
while ( (nBytes = read( h, bytes, chunk_size ) ) > 0 )
{
chunk++;
write_chunk( bytes, newObj, chunk, nBytes );
memset( bytes, 0xFF, chunk_size );
}
if ( nBytes < 0 )
error = nBytes;
printf( "%d data chunks writtenn", chunk );
}else {
perror( "Error opening file.n" );
}
close( h );
}
}else if ( S_ISSOCK( stats.st_mode ) )
{
printf( "socketn" );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL );
}else if ( S_ISFIFO( stats.st_mode ) )
{
printf( "fifon" );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL );
}else if ( S_ISCHR( stats.st_mode ) )
{
printf( "character devicen" );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL );
}else if ( S_ISBLK( stats.st_mode ) )
{
printf( "block devicen" );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL );
}else if ( S_ISDIR( stats.st_mode ) )
{
printf( "directoryn" );
error = write_object_header( newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL );
/* NCB modified 10/9/2001 process_directory(1,full_name); */
process_directory( newObj, full_name );
}
}
}else {
printf( " we don’t handle this typen" );
}
}
}
}
return(0);
}
#define STRN_SAME( dst, src ) (0 == strncmp( dst, src, strlen( src ) ) )
#define STR_SAME( dst, src ) (0 == strcmp( dst, src ) )
int main( int argc, char *argv[] )
{
struct stat stats;
printf( "mkyaffs2image: image building tool for YAFFS2 built "__DATE__ " "__TIME__ "n" );
if ( argc < 4 )
{
printf( "usage: mkyaffs2image dir image_file chunk_size [notagecc] [convert]n" );
printf( " dir the directory tree to be convertedn" );
printf( " image_file the output file to hold the imagen" );
printf( " ’2k’ or ’4k’ or ’8k’ (’2048′ or ’4096′ or ’8192′) the chunk(page) sizen" );
printf( " ‘notagecc’ disable ecc on tagn" );
printf( " ‘convert’ produce a big-endian image from a little-endian machinen" );
exit( 1 );
}
/* parse chunk (page) and spare size */
if ( STRN_SAME( argv[3], "2k" ) || STRN_SAME( argv[3], "2048" ) )
{
chunk_size = CHUNKSIZE_2K;
spare_size = SPARESIZE_64;
}else
if ( STRN_SAME( argv[3], "4k" ) || STRN_SAME( argv[3], "4096" ) )
{
chunk_size = CHUNKSIZE_4K;
spare_size = SPARESIZE_128;
}else
if ( STRN_SAME( argv[3], "8k" ) || STRN_SAME( argv[3], "8192" ) )
{
chunk_size = CHUNKSIZE_8K;
spare_size = SPARESIZE_256;
}else {
printf( "Unrecognized chunk(page) size: %sn", argv[3] );
exit( 1 );
}
/* parse optitional parameter */
if ( argc == 5 )
{
if ( STRN_SAME( argv[4], "convert" ) )
{
convert_endian = 1;
}else
if ( STRN_SAME( argv[4], "notagecc" ) )
{
ecc_on_tag = 0;
}else {
printf( "Unrecognized parameter: %sn", argv[4] );
exit( 1 );
}
}else
if ( argc == 6 )
{
if ( STRN_SAME( argv[4], "convert" ) )
{
convert_endian = 1;
if ( STRN_SAME( argv[5], "notagecc" ) )
{
ecc_on_tag = 0;
}else {
printf( "Unrecognized parameter: %sn", argv[5] );
exit( 1 );
}
}else
if ( STRN_SAME( argv[4], "notagecc" ) )
{
ecc_on_tag = 0;
if ( STRN_SAME( argv[5], "convert" ) )
{
convert_endian = 1;
}else {
printf( "Unrecognized parameter: %sn", argv[5] );
exit( 1 );
}
}else {
printf( "Unrecognized parameter: %sn", argv[4] );
exit( 1 );
}
}
if ( stat( argv[1], &stats ) < 0 )
{
printf( "Could not stat %sn", argv[1] );
exit( 1 );
}
if ( !S_ISDIR( stats.st_mode ) )
{
printf( " %s is not a directoryn", argv[1] );
exit( 1 );
}
outFile = open( argv[2], O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE );
if ( outFile < 0 )
{
printf( "Could not open output file %sn", argv[2] );
exit( 1 );
}
printf( "Processing directory %s into image file %sn", argv[1], argv[2] );
error = write_object_header( YAFFS_OBJECTID_ROOT, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1, "", -1, NULL );
if ( error )
error = process_directory( YAFFS_OBJECTID_ROOT, argv[1] );
close( outFile );
if ( error < 0 )
{
perror( "operation incomplete !" );
exit( 1 );
}else {
printf( "Operation complete.n"
"%d objects in %d directoriesn"
"%d NAND pagesn"
"total chunk size: 0x%xn"
"total image file size: 0x%xn", nObjects, nDirectories, nPages, chunk_size * nPages, (chunk_size + spare_size) * nPages );
}
close( outFile );
exit( 0 );
}转载请注明:在路上 » 【代码】修改后的mkyaffs2image.c,使其生成的makeyaffs2image支持2k/4k/8k pagesize的nand flash