cd4b906f2ba78c774c02230cd063ce0a581f31ce
[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 General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  */
14 #include <string.h>
15 #include <stdio.h>
16 #include "yaffs_guts.h"
17
18 const char *yboot_c_version="$Id: yboot.c,v 1.1 2003-01-21 03:32:17 charles Exp $";
19
20
21 #define MAX_FILE_SIZE   4000000
22 #define MAX_CHUNKS      (MAX_FILE_SIZE/YAFFS_BYTES_PER_CHUNK + 1)
23
24 static int chunkLocations[MAX_CHUNKS];
25
26
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);
30
31 static const char yaffs_countBits[256] =
32 {
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
49 };
50
51
52 static void spareToTags(yaffs_Spare *spare, yaffs_Tags *tag)
53 {
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;
63 }
64
65
66
67 // yboot_ScanForFile finds
68 static int yaffsboot_ScanForFile(yaffs_Device *dev, const char *fileName)
69 {
70         int pg;
71         int blk;
72         yaffs_ObjectHeader data;
73         yaffs_Spare spare;
74         yaffs_Tags tags;
75
76
77         if (!fileName)
78         {
79                 //printf("NULL filename\n");
80                 return -1;
81         }
82
83
84
85         //printf("Searching block range %d to %d for %s\n", dev->startBlock, dev->endBlock, fileName);
86
87         for (blk = dev->startBlock; blk < dev->endBlock; blk++)
88         {
89         
90                 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
91                 {
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
95                         {
96                                 spareToTags(&spare, &tags);
97                                 
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
101                                 )
102                                 {
103                                         //printf("%s found at chunk %x objectId is %x\n", fileName, blk* YAFFS_PAGES_PER_BLOCK + pg, tag.objectId);
104                                         
105                                         return tags.objectId;
106                                 }
107                         }
108                 }
109         }
110         // Sad day... not found.
111         // printf("%s not found\n",filename);
112         return -1;
113 }
114
115
116
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;
122
123 static yaffs_Device *bufferDevice;
124
125 static int chunkEnd = -1;
126 static int topChunk = -1;
127 static int fileSize = -1;
128
129 int yaffsboot_InitFile(yaffs_Device *dev, const char *fileName,int *loadedFileSize)
130 {
131
132         yaffs_Spare spare;
133         yaffs_Tags  tags;
134         int fileObjId;
135         int i;
136         
137         int blk;
138         int pg;
139         int missing;
140         int chunksMissing = 0;
141
142         bufferDevice = dev;     
143         
144         fileObjId = yaffsboot_ScanForFile(dev,fileName);
145
146         if(fileObjId < 0)
147         {
148                 return -1;
149         }
150         
151
152
153         //printf("Gathering chunks...\n");
154         
155         for (i = 0; i < MAX_CHUNKS; i++)
156         {
157                 chunkLocations[i] = -1;
158         }
159
160
161         for (blk = dev->startBlock; blk <= dev->endBlock; blk++)
162         {
163                 for (pg = 0; pg < YAFFS_CHUNKS_PER_BLOCK; pg++)
164                 {
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)
168                         {
169                                 spareToTags(&spare, &tags);
170
171                                 if (tags.objectId == fileObjId && tags.chunkId > 0)
172                                 {
173
174                                         if(tags.chunkId >= MAX_CHUNKS)
175                                         {
176                                                 printf("Chunk %d out of bounds (max is %d)\n",tags.chunkId, MAX_CHUNKS - 1);
177                                                 return -1;
178                                         }
179
180                                         chunkLocations[tags.chunkId] = (blk*32) + pg;
181                                         
182                                         chunkEnd = (tags.chunkId -1) * YAFFS_BYTES_PER_CHUNK + tags.byteCount;
183                                         
184                                         if(chunkEnd > fileSize) fileSize = chunkEnd;
185                                         
186                                         if(tags.chunkId > topChunk) topChunk = tags.chunkId;
187                                 }
188                         }
189                 }
190         }
191
192
193         for (missing= 0, i= 1; i<= topChunk; i++)
194         {
195                 if (chunkLocations[i] < 0)
196                 {
197                         //printf("chunk %x missing\n",i);
198                         chunksMissing++;
199                 }
200         }
201
202         *loadedFileSize = fileSize;
203         
204         return fileObjId;
205 }
206
207
208
209 int yaffsboot_Reinitialise(void)
210 {
211         bufferInitialised = 0;
212         return 0;
213 }
214
215
216 int yaffsboot_ReadByte(unsigned char *bPtr)
217 {
218         if(!bufferInitialised)
219         {
220                 //printf("Read buffer initialisation\n");
221                 bufferInitialised = 1;
222                 bufferChunk = 0;
223                 bufferLength = 0;
224                 bufferPos = -1;
225         }
226
227         if(bufferPos < 0)
228         {
229                 bufferChunk++;
230                 if(bufferChunk> topChunk)
231                 {
232                         printf("Chunk %d past end of file\r\n",bufferChunk);
233
234                         return -1;
235                 }
236
237                 if (chunkLocations[bufferChunk] < 0)
238                 {
239                                 printf("No chunk %d, zero page\n",bufferChunk);
240                                 memset(bufferData,0,YAFFS_BYTES_PER_CHUNK);
241                                 bufferLength = YAFFS_BYTES_PER_CHUNK;
242                 }
243                 else
244                 {
245                         yaffs_Spare localSpare;
246                         yaffs_Tags tags;
247                         __u8 calcEcc[3];
248
249                         bufferDevice->readChunkFromNAND(bufferDevice, chunkLocations[bufferChunk], bufferData, &localSpare);
250
251                         spareToTags(&localSpare, &tags);
252
253                         if(0 && bufferChunk <topChunk)
254                         {
255                                 bufferLength = YAFFS_BYTES_PER_CHUNK;
256                         }
257                         else
258                         {
259                                 bufferLength = tags.byteCount;
260                         }
261
262                         //printf("Read chunk %d, size %d bytes\n",bufferChunk,bufferLength);
263
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);
268                 }
269
270                 bufferPos = 0;
271
272                 if(bufferLength <= bufferPos)
273                 {
274                         return -1;
275                 }
276         }
277
278         *bPtr = bufferData[bufferPos];
279         bufferPos++;
280         if(bufferPos >= bufferLength)
281         {
282                 //printf("End of page %d at byte %d\r\n",bufferChunk,bufferLength);
283                 bufferPos = -1;
284         }
285         return 0;
286 }
287
288
289
290