Merge branch 'org.openembedded.dev' of git@git.openembedded.net:/openembedded into...
[vuplus_openembedded] / packages / dreambox / dreambox-buildimage-native / buildimage.c
1 /*
2  * buildimage - create Dreambox nand boot image.
3  *
4  * contains algorithms ripped from u-boot and first-stage.
5  * Licensed as GPL.
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <netinet/in.h>
13
14 int eraseblock_size, spare_size, sector_size, largepage;
15
16 #define SECTOR_SIZE_WITH_ECC (sector_size+spare_size)
17
18
19 /*
20  * Pre-calculated 256-way 1 byte column parity
21  */
22 static const unsigned char nand_ecc_precalc_table[] = {
23         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
24         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
25         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
26         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
27         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
28         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
29         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
30         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
31         0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
32         0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
33         0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
34         0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
35         0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
36         0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
37         0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
38         0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
39 };
40
41
42 /*
43  * Creates non-inverted ECC code from line parity
44  */
45 static void nand_trans_result(unsigned char reg2, unsigned char reg3,
46         unsigned char *ecc_code)
47 {
48         unsigned char a, b, i, tmp1, tmp2;
49
50         /* Initialize variables */
51         a = b = 0x80;
52         tmp1 = tmp2 = 0;
53
54         /* Calculate first ECC byte */
55         for (i = 0; i < 4; i++) {
56                 if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
57                         tmp1 |= b;
58                 b >>= 1;
59                 if (reg2 & a)           /* LP14,12,10,8 --> ecc_code[0] */
60                         tmp1 |= b;
61                 b >>= 1;
62                 a >>= 1;
63         }
64
65         /* Calculate second ECC byte */
66         b = 0x80;
67         for (i = 0; i < 4; i++) {
68                 if (reg3 & a)           /* LP7,5,3,1 --> ecc_code[1] */
69                         tmp2 |= b;
70                 b >>= 1;
71                 if (reg2 & a)           /* LP6,4,2,0 --> ecc_code[1] */
72                         tmp2 |= b;
73                 b >>= 1;
74                 a >>= 1;
75         }
76
77         /* Store two of the ECC bytes */
78         ecc_code[0] = tmp1;
79         ecc_code[1] = tmp2;
80 }
81
82 /*
83  * Calculate 3 byte ECC code for 256 byte block
84  */
85 static void nand_calculate_ecc (const unsigned char *dat, unsigned char *ecc_code)
86 {
87         unsigned char idx, reg1, reg3;
88         int j;
89
90         /* Initialize variables */
91         reg1 = reg3 = 0;
92         ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
93
94         /* Build up column parity */
95         for(j = 0; j < 256; j++) {
96
97                 /* Get CP0 - CP5 from table */
98                 idx = nand_ecc_precalc_table[dat[j]];
99                 reg1 ^= idx;
100
101                 /* All bit XOR = 1 ? */
102                 if (idx & 0x40) {
103                         reg3 ^= (unsigned char) j;
104                 }
105         }
106
107         /* Create non-inverted ECC code from line parity */
108         nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
109
110         /* Calculate final ECC code */
111         ecc_code[0] = ~ecc_code[0];
112         ecc_code[1] = ~ecc_code[1];
113         ecc_code[2] = ((~reg1) << 2) | 0x03;
114 }
115
116 void file_open(FILE **f, int *size, const char *filename)
117 {
118         *f = fopen(filename, "r");
119         if (!*f)
120         {
121                 perror(filename);
122                 exit(1);
123         }
124         fseek(*f, 0, SEEK_END);
125         *size = ftell(*f);
126         fseek(*f, 0, SEEK_SET);
127 }
128
129 void die(const char *msg)
130 {
131         fprintf(stderr, "%s\n", msg);
132         exit(2);
133 }
134
135 void emit_4(unsigned long val)
136 {
137         val = htonl(val);
138         write(1, &val, 4);
139 }
140
141 #define TO_SECT(x) (x+sector_size-1)/sector_size
142
143 typedef void fnc_encode_ecc(unsigned char *dst, unsigned char *src, int cnt);
144
145 void encode_hevers(unsigned char *dst, unsigned char *src, int count)
146 {
147         if (!largepage)
148         {
149                 dst[0] = count >> 8;
150                 dst[1] = count & 0xFF;
151                 unsigned char temp;
152                 int cnt;
153                 for(cnt=0; cnt<sector_size; cnt++)
154                 {
155                         temp=src[cnt];
156                         dst[2]^=temp;
157                         if(cnt & 1) 
158                                 dst[6 + 0]^=temp;
159                         else 
160                                 dst[6 + 1]^=temp;
161                         if(cnt & 2) dst[6 + 2]^=temp;
162                         if(cnt & 4) dst[6 + 3]^=temp;
163                         if(cnt & 8) dst[6 + 4]^=temp;
164                         if(cnt & 16) dst[6 + 5]^=temp;
165                         if(cnt & 32) dst[6 + 6]^=temp;
166                         if(cnt & 64) dst[6 + 7]^=temp;
167                         if(cnt & 128) dst[6 + 8]^=temp;
168                         if(cnt & 256) dst[6 + 9]^=temp;
169                 }
170         } else
171         {
172                 dst[0] = 0xFF;
173                 dst[1] = 0xFF;
174                 dst[2] = count >> 8;
175                 dst[3] = count & 0xFF;
176                 unsigned char temp;
177                 int cnt;
178                 for(cnt=0; cnt<sector_size; cnt++)
179                 {
180                         temp=src[cnt];
181                         dst[40]^=temp;
182                         if(cnt & 1) 
183                                 dst[41]^=temp;
184                         else 
185                                 dst[42]^=temp;
186                         if(cnt & 2) dst[43]^=temp;
187                         if(cnt & 4) dst[44]^=temp;
188                         if(cnt & 8) dst[45]^=temp;
189                         if(cnt & 16) dst[46]^=temp;
190                         if(cnt & 32) dst[47]^=temp;
191                         if(cnt & 64) dst[48]^=temp;
192                         if(cnt & 128) dst[49]^=temp;
193                         if(cnt & 256) dst[50]^=temp;
194                 }
195         }
196 }
197
198 void encode_jffs2(unsigned char *dst, unsigned char *src, int cnt)
199 {
200         memset(dst, 0xFF, spare_size);
201
202         if (!largepage)
203         {
204                 unsigned char ecc_code[8];
205                 nand_calculate_ecc (src, ecc_code);
206                 nand_calculate_ecc (src+256, ecc_code+3);
207                 dst[0] = ecc_code[0];
208                 dst[1] = ecc_code[1];
209                 dst[2] = ecc_code[2];
210                 dst[3] = ecc_code[3];
211                 dst[4] = 0xFF;
212                 dst[5] = 0xFF;
213                 dst[6] = ecc_code[4];
214                 dst[7] = ecc_code[5];
215
216                 if (!(cnt & ((eraseblock_size/sector_size)-1)))
217                 {
218                         dst[8]  = 0x19;
219                         dst[9]  = 0x85;
220                         dst[10] = 0x20;
221                         dst[11] = 0x03;
222                         dst[12] = 0x00;
223                         dst[13] = 0x00;
224                         dst[14] = 0x00;
225                         dst[15] = 0x08;
226                 } else
227                         memset(dst + 8, 0xFF, 8);
228         } else
229         {
230                 int i;
231                 for (i=0; i<8; ++i)
232                         nand_calculate_ecc (src + i * 256, dst + 40 + i * 3);
233
234                 if (!(cnt & ((eraseblock_size/sector_size)-1)))
235                 {
236                         dst[2] = 0x19;
237                         dst[3] = 0x85;
238                         dst[4] = 0x20;
239                         dst[5] = 0x03;
240                         dst[6] = 0x00;
241                         dst[7] = 0x00;
242                         dst[8] = 0x00;
243                         dst[9] = 0x08;
244                 }
245         }
246 }
247
248 void emit_file(FILE *src, int size, fnc_encode_ecc * eccfnc)
249 {
250         emit_4(size * SECTOR_SIZE_WITH_ECC);
251         int cnt = 0;
252         while (1)
253         {
254                 unsigned char sector[sector_size + spare_size];
255                 memset(sector, 0xFF, sector_size + spare_size);
256                 int r = fread(sector, 1, sector_size, src);
257                 if (!r)
258                         break;
259                 eccfnc(sector + sector_size, sector, cnt);
260                 write(1, sector, SECTOR_SIZE_WITH_ECC);
261                 ++cnt;
262         }
263         if (cnt != size)
264                 die("size changed");
265 }
266
267         /* reserve to two sectors plus 1% for badblocks, and round down */
268 #define BADBLOCK_SAFE(x) ( ((x) - (eraseblock_size * 2) - (x) / 100) &~ eraseblock_size )
269
270 int main(int argc, char **argv)
271 {
272         if ((argc != 4) && (argc != 5) && (argc != 6) && (argc != 7) )
273         {
274                 fprintf(stderr, "usage: %s <2nd.bin.gz> <boot.jffs2> <root.jffs2> [<arch>] [<flashsize-in-mb>] [options]> image.nfi\n", *argv);
275                 return 1;
276         }
277
278         FILE *f_2nd, *f_boot, *f_root;
279         int size_2nd, size_boot, size_root;
280
281         file_open(&f_2nd, &size_2nd, argv[1]);
282         file_open(&f_boot, &size_boot, argv[2]);
283         file_open(&f_root, &size_root, argv[3]);
284
285         int flashsize = 32*1024*1024;
286         if (argc >= 6)
287                 flashsize = atoi(argv[5]) * 1024 * 1024;
288
289
290         int partition[] = {0x40000, 0x400000, flashsize};
291
292         if ((argc >= 7) && strstr(argv[6], "large"))
293         {
294                 largepage = 1;
295                 eraseblock_size = 128*1024;
296                 spare_size = 64;
297                 sector_size = 2048;
298                 partition[0] = 0x100000;
299         } else
300         {
301                 largepage = 0;
302                 eraseblock_size = 16384;
303                 spare_size = 16;
304                 sector_size = 512;
305                 partition[0] = 0x40000;
306         }
307
308         if (size_2nd > BADBLOCK_SAFE(partition[0]))
309                 die("2nd stage is too big. did you gzip it before?");
310         if (size_boot > BADBLOCK_SAFE(partition[1] - partition[0]))
311                 die("boot is too big. You can modify the buildimage tool, but you don't want that.");
312         if (size_root > BADBLOCK_SAFE(partition[2] - partition[1]))
313                 die("root is too big. This doesn't work. sorry.");
314
315         int sectors_2nd = TO_SECT(size_2nd), sectors_boot = TO_SECT(size_boot), sectors_root = TO_SECT(size_root);
316
317         int num_partitions = 3;
318
319         int total_size = 4 + num_partitions * 4 + 4 + sectors_2nd * SECTOR_SIZE_WITH_ECC + 4 + sectors_boot * SECTOR_SIZE_WITH_ECC + 4 + sectors_root * SECTOR_SIZE_WITH_ECC;
320
321                 /* in case an architecture is given, write NFI1 header */
322         if (argc >= 5)
323         {
324                 char header[32] = "NFI1";
325                 strncpy(header + 4, argv[4], 28);
326                 write(1, header, 32);
327         }
328
329                 /* global header */
330         emit_4(total_size);
331
332                 /* partition */
333         emit_4(num_partitions * 4);
334         int i;
335         for (i=0; i < num_partitions; ++i)
336                 emit_4(partition[i]);
337
338                 /* 2nd stage */
339         emit_file(f_2nd, sectors_2nd, encode_hevers);
340                 /* boot + root */
341         emit_file(f_boot, sectors_boot, encode_jffs2);
342         emit_file(f_root, sectors_root, encode_jffs2);
343
344         return 0;
345 }