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