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