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