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 General Public License version 2 as
11 * published by the Free Software Foundation.
16 #include "yaffs_guts.h"
18 const char *yboot_c_version="$Id: yboot.c,v 1.1 2003-01-21 03:32:17 charles Exp $";
21 #define MAX_FILE_SIZE 4000000
22 #define MAX_CHUNKS (MAX_FILE_SIZE/YAFFS_BYTES_PER_CHUNK + 1)
24 static int chunkLocations[MAX_CHUNKS];
27 // External functions for ECC on data
28 void nand_calculate_ecc (const unsigned char*dat, unsigned char*ecc_code);
29 int nand_correct_data (unsigned char*dat, unsigned char*read_ecc, unsigned char*calc_ecc);
31 static const char yaffs_countBits[256] =
33 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
34 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
35 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
36 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
37 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
38 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
39 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
40 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
41 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
42 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
43 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
44 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
45 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
46 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
47 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
48 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
52 static void spareToTags(yaffs_Spare *spare, yaffs_Tags *tag)
54 unsigned char *bytes = (char *)tag;
55 bytes[0] = spare->tagByte0;
56 bytes[1] = spare->tagByte1;
57 bytes[2] = spare->tagByte2;
58 bytes[3] = spare->tagByte3;
59 bytes[4] = spare->tagByte4;
60 bytes[5] = spare->tagByte5;
61 bytes[6] = spare->tagByte6;
62 bytes[7] = spare->tagByte7;
67 // yboot_ScanForFile finds
68 static int yaffsboot_ScanForFile(yaffs_Device *dev, const char *fileName)
72 yaffs_ObjectHeader data;
79 //printf("NULL filename\n");
85 //printf("Searching block range %d to %d for %s\n", dev->startBlock, dev->endBlock, fileName);
87 for (blk = dev->startBlock; blk < dev->endBlock; blk++)
90 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
92 dev->readChunkFromNAND(dev, (blk*YAFFS_CHUNKS_PER_BLOCK) + pg, (__u8 *)&data, (yaffs_Spare *)&spare);
93 if (yaffs_countBits[spare.blockStatus] >=7 && // block OK
94 yaffs_countBits[spare.pageStatus] >= 7) // page ok
96 spareToTags(&spare, &tags);
98 if ( tags.chunkId == 0 && // it's a header
99 data.parentObjectId == YAFFS_OBJECTID_ROOT && // it's in the root
100 strcmp(data.name, fileName) == 0 // name matches
103 //printf("%s found at chunk %x objectId is %x\n", fileName, blk* YAFFS_PAGES_PER_BLOCK + pg, tag.objectId);
105 return tags.objectId;
110 // Sad day... not found.
111 // printf("%s not found\n",filename);
117 static unsigned char bufferData[YAFFS_BYTES_PER_CHUNK];
118 static int bufferPos = 0;
119 static int bufferChunk = 0;
120 static int bufferInitialised = 0;
121 static int bufferLength = 0;
123 static yaffs_Device *bufferDevice;
125 static int chunkEnd = -1;
126 static int topChunk = -1;
127 static int fileSize = -1;
129 int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName,int *loadedFileSize)
140 int chunksMissing = 0;
144 fileObjId = yaffsboot_ScanForFile(dev,fileName);
153 //printf("Gathering chunks...\n");
155 for (i = 0; i < MAX_CHUNKS; i++)
157 chunkLocations[i] = -1;
161 for (blk = dev->startBlock; blk <= dev->endBlock; blk++)
163 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
165 dev->readChunkFromNAND(dev, blk * YAFFS_CHUNKS_PER_BLOCK + pg, NULL, &spare);
166 if (yaffs_countBits[spare.blockStatus] >= 7 &&
167 yaffs_countBits[spare.pageStatus] >= 7)
169 spareToTags(&spare, &tags);
171 if (tags.objectId == fileObjId && tags.chunkId > 0)
174 if(tags.chunkId >= MAX_CHUNKS)
176 printf("Chunk %d out of bounds (max is %d)\n",tags.chunkId, MAX_CHUNKS - 1);
180 chunkLocations[tags.chunkId] = (blk*32) + pg;
182 chunkEnd = (tags.chunkId -1) * YAFFS_BYTES_PER_CHUNK + tags.byteCount;
184 if(chunkEnd > fileSize) fileSize = chunkEnd;
186 if(tags.chunkId > topChunk) topChunk = tags.chunkId;
193 for (missing= 0, i= 1; i<= topChunk; i++)
195 if (chunkLocations[i] < 0)
197 //printf("chunk %x missing\n",i);
202 *loadedFileSize = fileSize;
209 int yaffsboot_Reinitialise(void)
211 bufferInitialised = 0;
216 int yaffsboot_ReadByte(unsigned char *bPtr)
218 if(!bufferInitialised)
220 //printf("Read buffer initialisation\n");
221 bufferInitialised = 1;
230 if(bufferChunk> topChunk)
232 printf("Chunk %d past end of file\r\n",bufferChunk);
237 if (chunkLocations[bufferChunk] < 0)
239 printf("No chunk %d, zero page\n",bufferChunk);
240 memset(bufferData,0,YAFFS_BYTES_PER_CHUNK);
241 bufferLength = YAFFS_BYTES_PER_CHUNK;
245 yaffs_Spare localSpare;
249 bufferDevice->readChunkFromNAND(bufferDevice, chunkLocations[bufferChunk], bufferData, &localSpare);
251 spareToTags(&localSpare, &tags);
253 if(0 && bufferChunk <topChunk)
255 bufferLength = YAFFS_BYTES_PER_CHUNK;
259 bufferLength = tags.byteCount;
262 //printf("Read chunk %d, size %d bytes\n",bufferChunk,bufferLength);
264 nand_calculate_ecc(bufferData,calcEcc);
265 nand_correct_data (bufferData,localSpare.ecc1, calcEcc);
266 nand_calculate_ecc(&bufferData[256],calcEcc);
267 nand_correct_data (&bufferData[256],localSpare.ecc2, calcEcc);
272 if(bufferLength <= bufferPos)
278 *bPtr = bufferData[bufferPos];
280 if(bufferPos >= bufferLength)
282 //printf("End of page %d at byte %d\r\n",bufferChunk,bufferLength);