2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
3 * yboot: A yaffs bootloader.
5 * Copyright (C) 2002 Aleph One Ltd.
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License version 2.1 as
11 * published by the Free Software Foundation.
14 * Note: This code (yboot.c) and YAFFS headers are LGPL, the rest of YAFFS C code is covered by GPL.
15 * The rationale behind this is to allow easy incorporation of yaffs booting with
21 #include "yaffs_guts.h"
23 const char *yboot_c_version="$Id: yboot.c,v 1.2 2005-07-19 19:51:57 charles Exp $";
26 #define MAX_FILE_SIZE 4000000
27 #define MAX_CHUNKS (MAX_FILE_SIZE/YAFFS_BYTES_PER_CHUNK + 1)
29 static int chunkLocations[MAX_CHUNKS];
32 // External functions for ECC on data
33 void nand_calculate_ecc (const unsigned char*dat, unsigned char*ecc_code);
34 int nand_correct_data (unsigned char*dat, unsigned char*read_ecc, unsigned char*calc_ecc);
36 static const char yaffs_countBits[256] =
38 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
39 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
40 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
41 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
42 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
43 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
44 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
45 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
46 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
47 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
48 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
49 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
50 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
51 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
52 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
53 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
57 static void spareToTags(yaffs_Spare *spare, yaffs_Tags *tag)
59 unsigned char *bytes = (char *)tag;
60 bytes[0] = spare->tagByte0;
61 bytes[1] = spare->tagByte1;
62 bytes[2] = spare->tagByte2;
63 bytes[3] = spare->tagByte3;
64 bytes[4] = spare->tagByte4;
65 bytes[5] = spare->tagByte5;
66 bytes[6] = spare->tagByte6;
67 bytes[7] = spare->tagByte7;
72 // yboot_ScanForFile finds
73 static int yaffsboot_ScanForFile(yaffs_Device *dev, const char *fileName)
77 yaffs_ObjectHeader data;
84 //printf("NULL filename\n");
90 //printf("Searching block range %d to %d for %s\n", dev->startBlock, dev->endBlock, fileName);
92 for (blk = dev->startBlock; blk < dev->endBlock; blk++)
95 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
97 dev->readChunkFromNAND(dev, (blk*YAFFS_CHUNKS_PER_BLOCK) + pg, (__u8 *)&data, (yaffs_Spare *)&spare);
98 if (yaffs_countBits[spare.blockStatus] >=7 && // block OK
99 yaffs_countBits[spare.pageStatus] >= 7) // page ok
101 spareToTags(&spare, &tags);
103 if ( tags.chunkId == 0 && // it's a header
104 data.parentObjectId == YAFFS_OBJECTID_ROOT && // it's in the root
105 strcmp(data.name, fileName) == 0 // name matches
108 //printf("%s found at chunk %x objectId is %x\n", fileName, blk* YAFFS_PAGES_PER_BLOCK + pg, tag.objectId);
110 return tags.objectId;
115 // Sad day... not found.
116 // printf("%s not found\n",filename);
122 static unsigned char bufferData[YAFFS_BYTES_PER_CHUNK];
123 static int bufferPos = 0;
124 static int bufferChunk = 0;
125 static int bufferInitialised = 0;
126 static int bufferLength = 0;
128 static yaffs_Device *bufferDevice;
130 static int chunkEnd = -1;
131 static int topChunk = -1;
132 static int fileSize = -1;
134 int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName,int *loadedFileSize)
145 int chunksMissing = 0;
149 fileObjId = yaffsboot_ScanForFile(dev,fileName);
158 //printf("Gathering chunks...\n");
160 for (i = 0; i < MAX_CHUNKS; i++)
162 chunkLocations[i] = -1;
166 for (blk = dev->startBlock; blk <= dev->endBlock; blk++)
168 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
170 dev->readChunkFromNAND(dev, blk * YAFFS_CHUNKS_PER_BLOCK + pg, NULL, &spare);
171 if (yaffs_countBits[spare.blockStatus] >= 7 &&
172 yaffs_countBits[spare.pageStatus] >= 7)
174 spareToTags(&spare, &tags);
176 if (tags.objectId == fileObjId && tags.chunkId > 0)
179 if(tags.chunkId >= MAX_CHUNKS)
181 printf("Chunk %d out of bounds (max is %d)\n",tags.chunkId, MAX_CHUNKS - 1);
185 chunkLocations[tags.chunkId] = (blk*32) + pg;
187 chunkEnd = (tags.chunkId -1) * YAFFS_BYTES_PER_CHUNK + tags.byteCount;
189 if(chunkEnd > fileSize) fileSize = chunkEnd;
191 if(tags.chunkId > topChunk) topChunk = tags.chunkId;
198 for (missing= 0, i= 1; i<= topChunk; i++)
200 if (chunkLocations[i] < 0)
202 //printf("chunk %x missing\n",i);
207 *loadedFileSize = fileSize;
214 int yaffsboot_Reinitialise(void)
216 bufferInitialised = 0;
221 int yaffsboot_ReadByte(unsigned char *bPtr)
223 if(!bufferInitialised)
225 //printf("Read buffer initialisation\n");
226 bufferInitialised = 1;
235 if(bufferChunk> topChunk)
237 printf("Chunk %d past end of file\r\n",bufferChunk);
242 if (chunkLocations[bufferChunk] < 0)
244 printf("No chunk %d, zero page\n",bufferChunk);
245 memset(bufferData,0,YAFFS_BYTES_PER_CHUNK);
246 bufferLength = YAFFS_BYTES_PER_CHUNK;
250 yaffs_Spare localSpare;
254 bufferDevice->readChunkFromNAND(bufferDevice, chunkLocations[bufferChunk], bufferData, &localSpare);
256 spareToTags(&localSpare, &tags);
258 if(0 && bufferChunk <topChunk)
260 bufferLength = YAFFS_BYTES_PER_CHUNK;
264 bufferLength = tags.byteCount;
267 //printf("Read chunk %d, size %d bytes\n",bufferChunk,bufferLength);
269 nand_calculate_ecc(bufferData,calcEcc);
270 nand_correct_data (bufferData,localSpare.ecc1, calcEcc);
271 nand_calculate_ecc(&bufferData[256],calcEcc);
272 nand_correct_data (&bufferData[256],localSpare.ecc2, calcEcc);
277 if(bufferLength <= bufferPos)
283 *bPtr = bufferData[bufferPos];
285 if(bufferPos >= bufferLength)
287 //printf("End of page %d at byte %d\r\n",bufferChunk,bufferLength);