Merge branch 'master' of rsync://rsync.denx.de/git/u-boot
[platform/kernel/u-boot.git] / board / esd / common / auto_update.c
1 /*
2  * (C) Copyright 2003-2004
3  * Gary Jennejohn, DENX Software Engineering, gj@denx.de.
4  * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26
27 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
28 #warning CFG_NAND_LEGACY not defined in a file using the legacy NAND support!
29 #endif
30
31 #include <command.h>
32 #include <image.h>
33 #include <asm/byteorder.h>
34 #include <linux/mtd/nand_legacy.h>
35 #include <fat.h>
36
37 #include "auto_update.h"
38
39 #ifdef CONFIG_AUTO_UPDATE
40
41 #if !(CONFIG_COMMANDS & CFG_CMD_FAT)
42 #error "must define CFG_CMD_FAT"
43 #endif
44
45 extern au_image_t au_image[];
46 extern int N_AU_IMAGES;
47
48 #define AU_DEBUG
49 #undef AU_DEBUG
50
51 #undef debug
52 #ifdef  AU_DEBUG
53 #define debug(fmt,args...)      printf (fmt ,##args)
54 #else
55 #define debug(fmt,args...)
56 #endif  /* AU_DEBUG */
57
58
59 #define LOAD_ADDR ((unsigned char *)0x100000)   /* where to load files into memory */
60 #define MAX_LOADSZ 0x1e00000
61
62 /* externals */
63 extern int fat_register_device(block_dev_desc_t *, int);
64 extern int file_fat_detectfs(void);
65 extern long file_fat_read(const char *, void *, unsigned long);
66 long do_fat_read (const char *filename, void *buffer, unsigned long maxsize, int dols);
67 #ifdef CONFIG_VFD
68 extern int trab_vfd (ulong);
69 extern int transfer_pic(unsigned char, unsigned char *, int, int);
70 #endif
71 extern int flash_sect_erase(ulong, ulong);
72 extern int flash_sect_protect (int, ulong, ulong);
73 extern int flash_write (char *, ulong, ulong);
74 /* change char* to void* to shutup the compiler */
75 extern block_dev_desc_t *get_dev (char*, int);
76
77 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
78 /* references to names in cmd_nand.c */
79 #define NANDRW_READ     0x01
80 #define NANDRW_WRITE    0x00
81 #define NANDRW_JFFS2    0x02
82 #define NANDRW_JFFS2_SKIP       0x04
83 extern struct nand_chip nand_dev_desc[];
84 extern int nand_legacy_rw(struct nand_chip* nand, int cmd, size_t start, size_t len,
85                    size_t * retlen, u_char * buf);
86 extern int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
87 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY) */
88
89 extern block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE];
90
91
92 int au_check_cksum_valid(int i, long nbytes)
93 {
94         image_header_t *hdr;
95         unsigned long checksum;
96
97         hdr = (image_header_t *)LOAD_ADDR;
98
99         if ((au_image[i].type == AU_FIRMWARE) && (au_image[i].size != ntohl(hdr->ih_size))) {
100                 printf ("Image %s has wrong size\n", au_image[i].name);
101                 return -1;
102         }
103
104         if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
105                 printf ("Image %s bad total SIZE\n", au_image[i].name);
106                 return -1;
107         }
108         /* check the data CRC */
109         checksum = ntohl(hdr->ih_dcrc);
110
111         if (crc32 (0, (uchar *)(LOAD_ADDR + sizeof(*hdr)), ntohl(hdr->ih_size))
112                 != checksum) {
113                 printf ("Image %s bad data checksum\n", au_image[i].name);
114                 return -1;
115         }
116         return 0;
117 }
118
119
120 int au_check_header_valid(int i, long nbytes)
121 {
122         image_header_t *hdr;
123         unsigned long checksum;
124
125         hdr = (image_header_t *)LOAD_ADDR;
126         /* check the easy ones first */
127 #undef CHECK_VALID_DEBUG
128 #ifdef CHECK_VALID_DEBUG
129         printf("magic %#x %#x ", ntohl(hdr->ih_magic), IH_MAGIC);
130         printf("arch %#x %#x ", hdr->ih_arch, IH_CPU_PPC);
131         printf("size %#x %#lx ", ntohl(hdr->ih_size), nbytes);
132         printf("type %#x %#x ", hdr->ih_type, IH_TYPE_KERNEL);
133 #endif
134         if (nbytes < sizeof(*hdr))
135         {
136                 printf ("Image %s bad header SIZE\n", au_image[i].name);
137                 return -1;
138         }
139         if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_CPU_PPC)
140         {
141                 printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name);
142                 return -1;
143         }
144         /* check the hdr CRC */
145         checksum = ntohl(hdr->ih_hcrc);
146         hdr->ih_hcrc = 0;
147
148         if (crc32 (0, (uchar *)hdr, sizeof(*hdr)) != checksum) {
149                 printf ("Image %s bad header checksum\n", au_image[i].name);
150                 return -1;
151         }
152         hdr->ih_hcrc = htonl(checksum);
153
154         /* check the type - could do this all in one gigantic if() */
155         if ((au_image[i].type == AU_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
156                 printf ("Image %s wrong type\n", au_image[i].name);
157                 return -1;
158         }
159         if ((au_image[i].type == AU_SCRIPT) && (hdr->ih_type != IH_TYPE_SCRIPT)) {
160                 printf ("Image %s wrong type\n", au_image[i].name);
161                 return -1;
162         }
163
164         /* recycle checksum */
165         checksum = ntohl(hdr->ih_size);
166
167 #if 0 /* test-only */
168         /* for kernel and app the image header must also fit into flash */
169         if (idx != IDX_DISK)
170                 checksum += sizeof(*hdr);
171         /* check the size does not exceed space in flash. HUSH scripts */
172         /* all have ausize[] set to 0 */
173         if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
174                 printf ("Image %s is bigger than FLASH\n", au_image[i].name);
175                 return -1;
176         }
177 #endif
178
179         return 0;
180 }
181
182
183 int au_do_update(int i, long sz)
184 {
185         image_header_t *hdr;
186         char *addr;
187         long start, end;
188         int off, rc;
189         uint nbytes;
190         int k;
191 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
192         int total;
193 #endif
194
195         hdr = (image_header_t *)LOAD_ADDR;
196
197         switch (au_image[i].type) {
198         case AU_SCRIPT:
199                 printf("Executing script %s\n", au_image[i].name);
200
201                 /* execute a script */
202                 if (hdr->ih_type == IH_TYPE_SCRIPT) {
203                         addr = (char *)((char *)hdr + sizeof(*hdr));
204                         /* stick a NULL at the end of the script, otherwise */
205                         /* parse_string_outer() runs off the end. */
206                         addr[ntohl(hdr->ih_size)] = 0;
207                         addr += 8;
208
209                         /*
210                          * Replace cr/lf with ;
211                          */
212                         k = 0;
213                         while (addr[k] != 0) {
214                                 if ((addr[k] == 10) || (addr[k] == 13)) {
215                                         addr[k] = ';';
216                                 }
217                                 k++;
218                         }
219
220                         run_command(addr, 0);
221                         return 0;
222                 }
223
224                 break;
225
226         case AU_FIRMWARE:
227         case AU_NOR:
228         case AU_NAND:
229                 start = au_image[i].start;
230                 end = au_image[i].start + au_image[i].size - 1;
231
232                 /*
233                  * do not update firmware when image is already in flash.
234                  */
235                 if (au_image[i].type == AU_FIRMWARE) {
236                         char *orig = (char*)start;
237                         char *new  = (char *)((char *)hdr + sizeof(*hdr));
238                         nbytes = ntohl(hdr->ih_size);
239
240                         while(--nbytes) {
241                                 if (*orig++ != *new++) {
242                                         break;
243                                 }
244                         }
245                         if (!nbytes) {
246                                 printf("Skipping firmware update - images are identical\n");
247                                 break;
248                         }
249                 }
250
251                 /* unprotect the address range */
252                 /* this assumes that ONLY the firmware is protected! */
253                 if (au_image[i].type == AU_FIRMWARE) {
254                         flash_sect_protect(0, start, end);
255                 }
256
257                 /*
258                  * erase the address range.
259                  */
260                 if (au_image[i].type != AU_NAND) {
261                         printf("Updating NOR FLASH with image %s\n", au_image[i].name);
262                         debug ("flash_sect_erase(%lx, %lx);\n", start, end);
263                         flash_sect_erase(start, end);
264                 } else {
265 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
266                         printf("Updating NAND FLASH with image %s\n", au_image[i].name);
267                         debug ("nand_legacy_erase(%lx, %lx);\n", start, end);
268                         rc = nand_legacy_erase (nand_dev_desc, start, end - start + 1, 0);
269                         debug ("nand_legacy_erase returned %x\n", rc);
270 #endif
271                 }
272
273                 udelay(10000);
274
275                 /* strip the header - except for the kernel and ramdisk */
276                 if (au_image[i].type != AU_FIRMWARE) {
277                         addr = (char *)hdr;
278                         off = sizeof(*hdr);
279                         nbytes = sizeof(*hdr) + ntohl(hdr->ih_size);
280                 } else {
281                         addr = (char *)((char *)hdr + sizeof(*hdr));
282                         off = 0;
283                         nbytes = ntohl(hdr->ih_size);
284                 }
285
286                 /*
287                  * copy the data from RAM to FLASH
288                  */
289                 if (au_image[i].type != AU_NAND) {
290                         debug ("flash_write(%p, %lx %x)\n", addr, start, nbytes);
291                         rc = flash_write((char *)addr, start, nbytes);
292                 } else {
293 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
294                         debug ("nand_legacy_rw(%p, %lx %x)\n", addr, start, nbytes);
295                         rc = nand_legacy_rw(nand_dev_desc, NANDRW_WRITE | NANDRW_JFFS2,
296                                      start, nbytes, (size_t *)&total, (uchar *)addr);
297                         debug ("nand_legacy_rw: ret=%x total=%d nbytes=%d\n", rc, total, nbytes);
298 #endif
299                 }
300                 if (rc != 0) {
301                         printf("Flashing failed due to error %d\n", rc);
302                         return -1;
303                 }
304
305                 /*
306                  * check the dcrc of the copy
307                  */
308                 if (au_image[i].type != AU_NAND) {
309                         rc = crc32 (0, (uchar *)(start + off), ntohl(hdr->ih_size));
310                 } else {
311 #if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
312                         rc = nand_legacy_rw(nand_dev_desc, NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP,
313                                      start, nbytes, (size_t *)&total, (uchar *)addr);
314                         rc = crc32 (0, (uchar *)(addr + off), ntohl(hdr->ih_size));
315 #endif
316                 }
317                 if (rc != ntohl(hdr->ih_dcrc)) {
318                         printf ("Image %s Bad Data Checksum After COPY\n", au_image[i].name);
319                         return -1;
320                 }
321
322                 /* protect the address range */
323                 /* this assumes that ONLY the firmware is protected! */
324                 if (au_image[i].type == AU_FIRMWARE) {
325                         flash_sect_protect(1, start, end);
326                 }
327
328                 break;
329
330         default:
331                 printf("Wrong image type selected!\n");
332         }
333
334         return 0;
335 }
336
337
338 static void process_macros (const char *input, char *output)
339 {
340         char c, prev;
341         const char *varname_start = NULL;
342         int inputcnt  = strlen (input);
343         int outputcnt = CFG_CBSIZE;
344         int state = 0;  /* 0 = waiting for '$'  */
345                         /* 1 = waiting for '(' or '{' */
346                         /* 2 = waiting for ')' or '}' */
347                         /* 3 = waiting for '''  */
348 #ifdef DEBUG_PARSER
349         char *output_start = output;
350
351         printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input), input);
352 #endif
353
354         prev = '\0';                    /* previous character   */
355
356         while (inputcnt && outputcnt) {
357             c = *input++;
358             inputcnt--;
359
360             if (state!=3) {
361             /* remove one level of escape characters */
362             if ((c == '\\') && (prev != '\\')) {
363                 if (inputcnt-- == 0)
364                         break;
365                 prev = c;
366                 c = *input++;
367             }
368             }
369
370             switch (state) {
371             case 0:                     /* Waiting for (unescaped) $    */
372                 if ((c == '\'') && (prev != '\\')) {
373                         state = 3;
374                         break;
375                 }
376                 if ((c == '$') && (prev != '\\')) {
377                         state++;
378                 } else {
379                         *(output++) = c;
380                         outputcnt--;
381                 }
382                 break;
383             case 1:                     /* Waiting for (        */
384                 if (c == '(' || c == '{') {
385                         state++;
386                         varname_start = input;
387                 } else {
388                         state = 0;
389                         *(output++) = '$';
390                         outputcnt--;
391
392                         if (outputcnt) {
393                                 *(output++) = c;
394                                 outputcnt--;
395                         }
396                 }
397                 break;
398             case 2:                     /* Waiting for )        */
399                 if (c == ')' || c == '}') {
400                         int i;
401                         char envname[CFG_CBSIZE], *envval;
402                         int envcnt = input-varname_start-1; /* Varname # of chars */
403
404                         /* Get the varname */
405                         for (i = 0; i < envcnt; i++) {
406                                 envname[i] = varname_start[i];
407                         }
408                         envname[i] = 0;
409
410                         /* Get its value */
411                         envval = getenv (envname);
412
413                         /* Copy into the line if it exists */
414                         if (envval != NULL)
415                                 while ((*envval) && outputcnt) {
416                                         *(output++) = *(envval++);
417                                         outputcnt--;
418                                 }
419                         /* Look for another '$' */
420                         state = 0;
421                 }
422                 break;
423             case 3:                     /* Waiting for '        */
424                 if ((c == '\'') && (prev != '\\')) {
425                         state = 0;
426                 } else {
427                         *(output++) = c;
428                         outputcnt--;
429                 }
430                 break;
431             }
432             prev = c;
433         }
434
435         if (outputcnt)
436                 *output = 0;
437
438 #ifdef DEBUG_PARSER
439         printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
440                 strlen(output_start), output_start);
441 #endif
442 }
443
444
445 /*
446  * this is called from board_init() after the hardware has been set up
447  * and is usable. That seems like a good time to do this.
448  * Right now the return value is ignored.
449  */
450 int do_auto_update(void)
451 {
452         block_dev_desc_t *stor_dev;
453         long sz;
454         int i, res, cnt, old_ctrlc, got_ctrlc;
455         char buffer[32];
456         char str[80];
457
458         /*
459          * Check whether a CompactFlash is inserted
460          */
461         if (ide_dev_desc[0].type == DEV_TYPE_UNKNOWN) {
462                 return -1;       /* no disk detected! */
463         }
464
465         /* check whether it has a partition table */
466         stor_dev = get_dev("ide", 0);
467         if (stor_dev == NULL) {
468                 debug ("Uknown device type\n");
469                 return -1;
470         }
471         if (fat_register_device(stor_dev, 1) != 0) {
472                 debug ("Unable to register ide disk 0:1 for fatls\n");
473                 return -1;
474         }
475
476         /*
477          * Check if magic file is present
478          */
479         if (do_fat_read(AU_MAGIC_FILE, buffer, sizeof(buffer), LS_NO) <= 0) {
480                 return -1;
481         }
482
483 #ifdef CONFIG_AUTO_UPDATE_SHOW
484         board_auto_update_show(1);
485 #endif
486         puts("\nAutoUpdate Disk detected! Trying to update system...\n");
487
488         /* make sure that we see CTRL-C and save the old state */
489         old_ctrlc = disable_ctrlc(0);
490
491         /* just loop thru all the possible files */
492         for (i = 0; i < N_AU_IMAGES; i++) {
493                 /*
494                  * Try to expand the environment var in the fname
495                  */
496                 process_macros(au_image[i].name, str);
497                 strcpy(au_image[i].name, str);
498
499                 printf("Reading %s ...", au_image[i].name);
500                 /* just read the header */
501                 sz = do_fat_read(au_image[i].name, LOAD_ADDR, sizeof(image_header_t), LS_NO);
502                 debug ("read %s sz %ld hdr %d\n",
503                         au_image[i].name, sz, sizeof(image_header_t));
504                 if (sz <= 0 || sz < sizeof(image_header_t)) {
505                         puts(" not found\n");
506                         continue;
507                 }
508                 if (au_check_header_valid(i, sz) < 0) {
509                         puts(" header not valid\n");
510                         continue;
511                 }
512                 sz = do_fat_read(au_image[i].name, LOAD_ADDR, MAX_LOADSZ, LS_NO);
513                 debug ("read %s sz %ld hdr %d\n",
514                         au_image[i].name, sz, sizeof(image_header_t));
515                 if (sz <= 0 || sz <= sizeof(image_header_t)) {
516                         puts(" not found\n");
517                         continue;
518                 }
519                 if (au_check_cksum_valid(i, sz) < 0) {
520                         puts(" checksum not valid\n");
521                         continue;
522                 }
523                 puts(" done\n");
524
525                 do {
526                         res = au_do_update(i, sz);
527                         /* let the user break out of the loop */
528                         if (ctrlc() || had_ctrlc()) {
529                                 clear_ctrlc();
530                                 if (res < 0)
531                                         got_ctrlc = 1;
532                                 break;
533                         }
534                         cnt++;
535                 } while (res < 0);
536         }
537
538         /* restore the old state */
539         disable_ctrlc(old_ctrlc);
540
541         puts("AutoUpdate finished\n\n");
542 #ifdef CONFIG_AUTO_UPDATE_SHOW
543         board_auto_update_show(0);
544 #endif
545
546         return 0;
547 }
548
549
550 int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
551 {
552         do_auto_update();
553
554         return 0;
555 }
556 U_BOOT_CMD(
557         autoupd,        1,      1,      auto_update,
558         "autoupd - Automatically update images\n",
559         NULL
560 );
561 #endif /* CONFIG_AUTO_UPDATE */