*** empty log message ***
[yaffs/.git] / direct / yboot.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  * yboot: A yaffs bootloader.
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
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.
12  *
13  *
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 
16  *       prorietary code.
17  *
18  */
19 #include <string.h>
20 #include <stdio.h>
21 #include "yaffs_guts.h"
22
23 const char *yboot_c_version="$Id: yboot.c,v 1.2 2005-07-19 19:51:57 charles Exp $";
24
25
26 #define MAX_FILE_SIZE   4000000
27 #define MAX_CHUNKS      (MAX_FILE_SIZE/YAFFS_BYTES_PER_CHUNK + 1)
28
29 static int chunkLocations[MAX_CHUNKS];
30
31
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);
35
36 static const char yaffs_countBits[256] =
37 {
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
54 };
55
56
57 static void spareToTags(yaffs_Spare *spare, yaffs_Tags *tag)
58 {
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;
68 }
69
70
71
72 // yboot_ScanForFile finds
73 static int yaffsboot_ScanForFile(yaffs_Device *dev, const char *fileName)
74 {
75         int pg;
76         int blk;
77         yaffs_ObjectHeader data;
78         yaffs_Spare spare;
79         yaffs_Tags tags;
80
81
82         if (!fileName)
83         {
84                 //printf("NULL filename\n");
85                 return -1;
86         }
87
88
89
90         //printf("Searching block range %d to %d for %s\n", dev->startBlock, dev->endBlock, fileName);
91
92         for (blk = dev->startBlock; blk < dev->endBlock; blk++)
93         {
94         
95                 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
96                 {
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
100                         {
101                                 spareToTags(&spare, &tags);
102                                 
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
106                                 )
107                                 {
108                                         //printf("%s found at chunk %x objectId is %x\n", fileName, blk* YAFFS_PAGES_PER_BLOCK + pg, tag.objectId);
109                                         
110                                         return tags.objectId;
111                                 }
112                         }
113                 }
114         }
115         // Sad day... not found.
116         // printf("%s not found\n",filename);
117         return -1;
118 }
119
120
121
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;
127
128 static yaffs_Device *bufferDevice;
129
130 static int chunkEnd = -1;
131 static int topChunk = -1;
132 static int fileSize = -1;
133
134 int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName,int *loadedFileSize)
135 {
136
137         yaffs_Spare spare;
138         yaffs_Tags  tags;
139         int fileObjId;
140         int i;
141         
142         int blk;
143         int pg;
144         int missing;
145         int chunksMissing = 0;
146
147         bufferDevice = dev;     
148         
149         fileObjId = yaffsboot_ScanForFile(dev,fileName);
150
151         if(fileObjId < 0)
152         {
153                 return -1;
154         }
155         
156
157
158         //printf("Gathering chunks...\n");
159         
160         for (i = 0; i < MAX_CHUNKS; i++)
161         {
162                 chunkLocations[i] = -1;
163         }
164
165
166         for (blk = dev->startBlock; blk <= dev->endBlock; blk++)
167         {
168                 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
169                 {
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)
173                         {
174                                 spareToTags(&spare, &tags);
175
176                                 if (tags.objectId == fileObjId && tags.chunkId > 0)
177                                 {
178
179                                         if(tags.chunkId >= MAX_CHUNKS)
180                                         {
181                                                 printf("Chunk %d out of bounds (max is %d)\n",tags.chunkId, MAX_CHUNKS - 1);
182                                                 return -1;
183                                         }
184
185                                         chunkLocations[tags.chunkId] = (blk*32) + pg;
186                                         
187                                         chunkEnd = (tags.chunkId -1) * YAFFS_BYTES_PER_CHUNK + tags.byteCount;
188                                         
189                                         if(chunkEnd > fileSize) fileSize = chunkEnd;
190                                         
191                                         if(tags.chunkId > topChunk) topChunk = tags.chunkId;
192                                 }
193                         }
194                 }
195         }
196
197
198         for (missing= 0, i= 1; i<= topChunk; i++)
199         {
200                 if (chunkLocations[i] < 0)
201                 {
202                         //printf("chunk %x missing\n",i);
203                         chunksMissing++;
204                 }
205         }
206
207         *loadedFileSize = fileSize;
208         
209         return fileObjId;
210 }
211
212
213
214 int yaffsboot_Reinitialise(void)
215 {
216         bufferInitialised = 0;
217         return 0;
218 }
219
220
221 int yaffsboot_ReadByte(unsigned char *bPtr)
222 {
223         if(!bufferInitialised)
224         {
225                 //printf("Read buffer initialisation\n");
226                 bufferInitialised = 1;
227                 bufferChunk = 0;
228                 bufferLength = 0;
229                 bufferPos = -1;
230         }
231
232         if(bufferPos < 0)
233         {
234                 bufferChunk++;
235                 if(bufferChunk> topChunk)
236                 {
237                         printf("Chunk %d past end of file\r\n",bufferChunk);
238
239                         return -1;
240                 }
241
242                 if (chunkLocations[bufferChunk] < 0)
243                 {
244                                 printf("No chunk %d, zero page\n",bufferChunk);
245                                 memset(bufferData,0,YAFFS_BYTES_PER_CHUNK);
246                                 bufferLength = YAFFS_BYTES_PER_CHUNK;
247                 }
248                 else
249                 {
250                         yaffs_Spare localSpare;
251                         yaffs_Tags tags;
252                         __u8 calcEcc[3];
253
254                         bufferDevice->readChunkFromNAND(bufferDevice, chunkLocations[bufferChunk], bufferData, &localSpare);
255
256                         spareToTags(&localSpare, &tags);
257
258                         if(0 && bufferChunk <topChunk)
259                         {
260                                 bufferLength = YAFFS_BYTES_PER_CHUNK;
261                         }
262                         else
263                         {
264                                 bufferLength = tags.byteCount;
265                         }
266
267                         //printf("Read chunk %d, size %d bytes\n",bufferChunk,bufferLength);
268
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);
273                 }
274
275                 bufferPos = 0;
276
277                 if(bufferLength <= bufferPos)
278                 {
279                         return -1;
280                 }
281         }
282
283         *bPtr = bufferData[bufferPos];
284         bufferPos++;
285         if(bufferPos >= bufferLength)
286         {
287                 //printf("End of page %d at byte %d\r\n",bufferChunk,bufferLength);
288                 bufferPos = -1;
289         }
290         return 0;
291 }
292
293
294
295